//#include "StdAfx.h"
#include "wintypes.h"
#include "emule.h"
#include "WebServer.h"
#include "XBMDraw.h"
#include "ED2KLink.h"
#include "MD5Sum.h"
#include <stdlib.h>
#include <wx/wfstream.h>
#include <wx/txtstrm.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#define HTTPInit "Server: eMule\r\nPragma: no-cache\r\nExpires: 0\r\nCache-Control: no-cache, no-store, must-revalidate\r\nConnection: close\r\nContent-Type: text/html\r\n"
#define HTTPInitGZ "Server: eMule\r\nPragma: no-cache\r\nExpires: 0\r\nCache-Control: no-cache, no-store, must-revalidate\r\nConnection: close\r\nContent-Type: text/html\r\nContent-Encoding: gzip\r\n"

#define WEB_SERVER_TEMPLATES_VERSION	2

static int dwThread = 0;

CWebServer::CWebServer(void)
{
	m_Params.bShowUploadQueue = false;

	m_Params.DownloadSort = DOWN_SORT_NAME;
	m_Params.bDownloadSortReverse = false;
	m_Params.ServerSort = SERVER_SORT_NAME;
	m_Params.bServerSortReverse = false;
	m_Params.SharedSort = SHARED_SORT_NAME;
	m_Params.bSharedSortReverse = false;
		
	dwThread = 0; //GetCurrentThreadId();
	m_bServerWorking = false;
}

void CWebServer::ReloadTemplates()
{
	wxString sFile = theApp.glob_prefs->GetAppDir() + wxString("eMule.tmpl");
	//CStdioFile file;
	//if(file.Open(sFile, CFile::modeRead|CFile::typeText))
	//{
	wxFileInputStream input(sFile);
	if(input.Ok()) {
		wxTextInputStream file(input);
		wxString sAll;
		while(!input.Eof()) 
		{
			wxString sLine;
			sLine=file.ReadString();

			sAll += sLine + "\n";
		}
		//file.Close();
		// it'll get closed sometime..
	
		wxString sVersion = _LoadTemplate(sAll,"TMPL_VERSION");
		long lVersion = atol(sVersion);
		if(lVersion < WEB_SERVER_TEMPLATES_VERSION)
		{
			//if(m_bServerWorking)
				//theApp.emuledlg->AddLogLine(true,GetResString(IDS_WS_ERR_LOADTEMPLATE),sFile);
		}
		else
		{
			m_Templates.sHeader = _LoadTemplate(sAll,"TMPL_HEADER");
			m_Templates.sHeaderMetaRefresh = _LoadTemplate(sAll,"TMPL_HEADER_META_REFRESH");
			m_Templates.sHeaderStylesheet = _LoadTemplate(sAll,"TMPL_HEADER_STYLESHEET");
			m_Templates.sFooter = _LoadTemplate(sAll,"TMPL_FOOTER");
			m_Templates.sServerList = _LoadTemplate(sAll,"TMPL_SERVER_LIST");
			m_Templates.sServerLine = _LoadTemplate(sAll,"TMPL_SERVER_LINE");
			m_Templates.sTransferImages = _LoadTemplate(sAll,"TMPL_TRANSFER_IMAGES");
			m_Templates.sTransferList = _LoadTemplate(sAll,"TMPL_TRANSFER_LIST");
			m_Templates.sTransferDownHeader = _LoadTemplate(sAll,"TMPL_TRANSFER_DOWN_HEADER");
			m_Templates.sTransferDownFooter = _LoadTemplate(sAll,"TMPL_TRANSFER_DOWN_FOOTER");
			m_Templates.sTransferDownLine = _LoadTemplate(sAll,"TMPL_TRANSFER_DOWN_LINE");
			m_Templates.sTransferDownLineGood = _LoadTemplate(sAll,"TMPL_TRANSFER_DOWN_LINE_GOOD");
			m_Templates.sTransferUpHeader = _LoadTemplate(sAll,"TMPL_TRANSFER_UP_HEADER");
			m_Templates.sTransferUpFooter = _LoadTemplate(sAll,"TMPL_TRANSFER_UP_FOOTER");
			m_Templates.sTransferUpLine = _LoadTemplate(sAll,"TMPL_TRANSFER_UP_LINE");
			m_Templates.sTransferUpQueueShow = _LoadTemplate(sAll,"TMPL_TRANSFER_UP_QUEUE_SHOW");
			m_Templates.sTransferUpQueueHide = _LoadTemplate(sAll,"TMPL_TRANSFER_UP_QUEUE_HIDE");
			m_Templates.sTransferUpQueueLine = _LoadTemplate(sAll,"TMPL_TRANSFER_UP_QUEUE_LINE");
			m_Templates.sTransferBadLink = _LoadTemplate(sAll,"TMPL_TRANSFER_BAD_LINK");
			m_Templates.sDownloadLink = _LoadTemplate(sAll,"TMPL_DOWNLOAD_LINK");
			m_Templates.sSharedList = _LoadTemplate(sAll,"TMPL_SHARED_LIST");
			m_Templates.sSharedLine = _LoadTemplate(sAll,"TMPL_SHARED_LINE");
			m_Templates.sSharedLineChanged = _LoadTemplate(sAll,"TMPL_SHARED_LINE_CHANGED");
			m_Templates.sGraphs = _LoadTemplate(sAll,"TMPL_GRAPHS");
			m_Templates.sLog = _LoadTemplate(sAll,"TMPL_LOG");
			m_Templates.sServerInfo = _LoadTemplate(sAll,"TMPL_SERVERINFO");
			m_Templates.sDebugLog = _LoadTemplate(sAll,"TMPL_DEBUGLOG");
			m_Templates.sStats = _LoadTemplate(sAll,"TMPL_STATS");
			m_Templates.sPreferences = _LoadTemplate(sAll,"TMPL_PREFERENCES");
			m_Templates.sLogin = _LoadTemplate(sAll,"TMPL_LOGIN");
			m_Templates.sConnectedServer = _LoadTemplate(sAll,"TMPL_CONNECTED_SERVER");
			m_Templates.sAddServerBox = _LoadTemplate(sAll,"TMPL_ADDSERVERBOX");
			m_Templates.sWebSearch = _LoadTemplate(sAll,"TMPL_WEBSEARCH");
			m_Templates.iProgressbarWidth=atoi(_LoadTemplate(sAll,"PROGRESSBARWIDTH"));
			m_Templates.sResDir = _LoadTemplate(sAll,"RESSOURCES_PATH");			
		}
	}
	//else
        //if(m_bServerWorking)
					//theApp.emuledlg->AddLogLine(true,GetResString(IDS_WEB_ERR_CANTLOAD), sFile);
}

CWebServer::~CWebServer(void)
{
	if (m_bServerWorking) StopSockets();
}

wxString CWebServer::_LoadTemplate(wxString sAll, wxString sTemplateName)
{
	wxString sRet = "";
	int nStart = sAll.Find("<--" + sTemplateName + "-->");
	int nEnd = sAll.Find("<--" + sTemplateName + "_END-->");
	if(nStart != -1 && nEnd != -1)
	{
		nStart += sTemplateName.Length() + 7;
		sRet = sAll.Mid(nStart, nEnd - nStart - 1);
	}
	
	if(sRet.IsEmpty())
	{
		if (sTemplateName=="TMPL_VERSION")
			theApp.emuledlg->AddLogLine(true,"Can't find template version number!\nPlease replace eMule.tmpl with a newer version!");
			theApp.emuledlg->AddDebugLogLine(false,"Failed to load template " + sTemplateName);
	}
	return sRet;
}

void CWebServer::StartServer(void)
{
	if(m_bServerWorking != theApp.glob_prefs->GetWSIsEnabled())
		m_bServerWorking = theApp.glob_prefs->GetWSIsEnabled();
	else
		return;

	if (m_bServerWorking) {
		ReloadTemplates();
		StartSockets(this);
	} else StopSockets();

	if(theApp.glob_prefs->GetWSIsEnabled())
		theApp.emuledlg->AddLogLine(false,"%s: %s",_GetPlainResString(IDS_PW_WS).GetData(), _GetPlainResString(IDS_ENABLED).GetData());
	else
		theApp.emuledlg->AddLogLine(false,"%s: %s",_GetPlainResString(IDS_PW_WS).GetData(), _GetPlainResString(IDS_DISABLED).GetData());
}

void CWebServer::_RemoveServer(wxString sIP)
{
	CServer* server=theApp.serverlist->GetServerByAddress((char*)sIP.GetData() ,0);
	//if (server!=NULL) theApp.emuledlg->SendMessage(WEB_REMOVE_SERVER, (WPARAM)server, NULL);
}

void CWebServer::_SetSharedFilePriority(wxString hash, uint8 priority)
{	
	CKnownFile* cur_file;
	uchar fileid[16];
	DecodeBase16(hash.GetData(),hash.Length(),fileid);

	cur_file=theApp.sharedfiles->GetFileByID(fileid);
	
	if (cur_file==0) return;

	if(priority >= 0 && priority < 5)
	{
#warning implementation still old one..		
		//cur_file->SetAutoUpPriority(false);
		//cur_file->SetUpPriority(priority);
	}
	else if(priority == 5)// && cur_file->IsPartFile())
	{
#warning implementation still old one..		
		//cur_file->SetAutoUpPriority(true);
		//cur_file->UpdateAutoUpPriority(); 
	}
}

void CWebServer::AddStatsLine(UpDown* line)
{
	m_Params.PointsForWeb.Add(line);
	if(m_Params.PointsForWeb.GetCount() > WEB_GRAPH_WIDTH) {
	  delete m_Params.PointsForWeb[0];
	  m_Params.PointsForWeb.RemoveAt(0);
	}
}

wxString CWebServer::_SpecialChars(wxString str) 
{
	str.Replace("&","&amp;");
	str.Replace("<","&lt;");
	str.Replace(">","&gt;");
	str.Replace("\"","&quot;");
	return str;
}

void CWebServer::_ConnectToServer(wxString sIP)
{
#if 0
	CServer* server=theApp.serverlist->GetServerByAddress(sIP.GetBuffer(),0);
	if (server!=NULL) theApp.emuledlg->SendMessage(WEB_CONNECT_TO_SERVER, (WPARAM)server, NULL);
#endif
}

void CWebServer::ProcessImgFileReq(ThreadData Data) {
	wxString filename=Data.sURL;
	wxString contenttype;

	printf("inc. fname=%s\n",filename.GetData());
	if (filename.Right(4).MakeLower()==".gif") contenttype="Content-Type: image/gif\r\n";
		else if (filename.Right(4).MakeLower()==".jpg"  || filename.Right(5).MakeLower()==".jpeg") contenttype="Content-Type: image/jpg\r\n";
		else if (filename.Right(4).MakeLower()==".bmp") contenttype="Content-Type: image/bmp\r\n";
		else if (filename.Right(4).MakeLower()==".png") contenttype="Content-Type: image/png";


	filename=filename.Right(filename.Length()-1);
	//filename.Replace("/","\\");
	filename=wxString(theApp.glob_prefs->GetAppDir())+"webserver/"+filename;
	printf("**** imgrequest: %s\n",filename.GetData());
	wxFileInputStream* fis = new wxFileInputStream(filename);
	if(fis->Ok()) {
	  fis->SeekI(0,wxFromEnd);
	  off_t koko=fis->TellI();
	  fis->SeekI(0,wxFromStart);
	  char* buffer=new char[koko];
	  fis->Read((void*)buffer,koko);
	  Data.pSocket->SendContent((char*)contenttype.GetData(),(void*)buffer,fis->LastRead());
	  delete fis;
	  delete buffer;
	}
	#if 0
	CFile file;
	if(file.Open(filename, CFile::modeRead|CFile::typeBinary))
	{
		char* buffer=new char[file.GetLength()];
		int size=file.Read(buffer,file.GetLength());
		file.Close();
		Data.pSocket->SendContent(contenttype, buffer, size);
		delete[] buffer;
	}
	#endif
}


void CWebServer::ProcessURL(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return;

#if 0	
	SetThreadLocale(theApp.glob_prefs->GetLanguageID());
	CoInitialize(NULL);
#endif

	bool isUseGzip = theApp.glob_prefs->GetWebUseGzip();
	wxString Out = "";
	wxString OutE = "";	// List Entry Templates
	wxString OutE2 = "";
	wxString OutS = "";	// ServerStatus Templates
	TCHAR *gzipOut = NULL;
	long gzipLen=0;
	
	CString HTTPProcessData = "";
	CString HTTPTemp = "";
	//char	HTTPTempC[100] = "";
	srand ( time(NULL) );

	long lSession = 0;
	if(_ParseURL(Data.sURL, "ses") != "")
		lSession = atol(_ParseURL(Data.sURL, "ses"));

	// WE CANT TOUCH THE MAIN THREAD'S GUI!!!
	if (_ParseURL(Data.sURL, "w") == "password")
	{
		wxString test=MD5Sum(_ParseURL(Data.sURL, "p")).GetHash();
		
			printf("*** testing PW: %s == %s\n",
				MD5Sum(_ParseURL(Data.sURL, "p")).GetHash().GetData(),
				theApp.glob_prefs->GetWSPass().GetData());
		if(MD5Sum(_ParseURL(Data.sURL, "p")).GetHash() == theApp.glob_prefs->GetWSPass())
		{
			Session* ses=new Session();;
			ses->admin=true;
			ses->startTime = time(NULL);//CTime::GetCurrentTime();
			ses->lSession = lSession = rand() * 10000L + rand();
			pThis->m_Params.Sessions.Add(ses);
			//theApp.emuledlg->serverwnd->UpdateMyInfo();
			//theApp.emuledlg->AddLogLine(true,GetResString(IDS_WEB_ADMINLOGIN));
		}
		else if(theApp.glob_prefs->GetWSIsLowUserEnabled() && theApp.glob_prefs->GetWSLowPass()!="" && MD5Sum(_ParseURL(Data.sURL, "p")).GetHash() == theApp.glob_prefs->GetWSLowPass())
		{
			Session* ses=new Session();
			ses->admin=false;
			ses->startTime = time(NULL);//CTime::GetCurrentTime();
			ses->lSession = lSession = rand() * 10000L + rand();
			pThis->m_Params.Sessions.Add(ses);
			//theApp.emuledlg->serverwnd->UpdateMyInfo();
			//theApp.emuledlg->AddLogLine(true,GetResString(IDS_WEB_GUESTLOGIN));
			}
		else {
		  //theApp.emuledlg->AddLogLine(true,GetResString(IDS_WEB_BADLOGINATTEMPT));
		}
		isUseGzip = false; // [Julien]
	}

	wxString sSession; sSession.Printf("%ld", lSession);

	if (_ParseURL(Data.sURL, "w") == "logout") 
		_RemoveSession(Data, lSession);
		
	if(_IsLoggedIn(Data, lSession))
	{
		Out += _GetHeader(Data, lSession);
		wxString sPage = _ParseURL(Data.sURL, "w");
		printf("***** logged in, getting page %s\n",sPage.GetData());
		printf("***** session is %s\n",sSession.GetData());
		
		if (sPage == "server") 
		{
			Out += _GetServerList(Data);
		}
		else
		if (sPage == "download") 
		{
			Out += _GetDownloadLink(Data);
		}
		else
		if (sPage == "shared") 
		{ 
			Out += _GetSharedFilesList(Data);
		}
		else
		if (sPage == "transfer") 
		{
			Out += _GetTransferList(Data);
		}
		else
		if (sPage == "websearch") 
		{
			Out += _GetWebSearch(Data);
		}
		else
		if (sPage == "search") 
		{
			Out += _GetSearch(Data);
		}
		else
		if (sPage == "graphs")
		{
			Out += _GetGraphs(Data);
		}
		else
		if (sPage == "log") 
		{
			Out += _GetLog(Data);
		}
		if (sPage == "sinfo") 
		{
			Out += _GetServerInfo(Data);
		}
		if (sPage == "debuglog") 
		{
			Out += _GetDebugLog(Data);
		}
		if (sPage == "stats") 
		{
			Out += _GetStats(Data);
		}
		if (sPage == "options") 
		{
			Out += _GetPreferences(Data);
		}
		Out += _GetFooter(Data);

		if (sPage == "")
			isUseGzip = false;

		if(isUseGzip)
		{
			bool bOk = false;
			try
			{
				uLongf destLen = Out.Length() + 1024;
				gzipOut = new TCHAR[destLen];
				if(_GzipCompress((Bytef*)gzipOut, &destLen, (const Bytef*)(TCHAR*)Out.GetData(), Out.Length(), Z_DEFAULT_COMPRESSION) == Z_OK)
				{
					bOk = true;
					gzipLen = destLen;
				}
			}
			catch(...)
			{
			}
			if(!bOk)
			{
				isUseGzip = false;
				if(gzipOut != NULL)
				{
					delete[] gzipOut;
					gzipOut = NULL;
				}
			}
		}
	}
	else 
	{
		isUseGzip = false;
		Out += _GetLoginScreen(Data);
	}

	// send answer ...
	if(!isUseGzip)
	{
		Data.pSocket->SendContent(HTTPInit, Out, Out.Length());
	}
	else
	{
		Data.pSocket->SendContent(HTTPInitGZ, gzipOut, gzipLen);
	}
	if(gzipOut != NULL)
		delete[] gzipOut;
}

wxString CWebServer::_ParseURL(wxString URL, wxString fieldname)
{
	wxString value = "";
	wxString Parameter = "";
	char fromReplace[4] = "";	// decode URL
	char toReplace[2] = "";		// decode URL
	int i = 0;
	int findPos = -1;
	int findLength = 0;

	printf("*** parsing url %s :: field %s\n",URL.GetData(),fieldname.GetData());
	if (URL.Find("?") > -1) {
		Parameter = URL.Mid(URL.Find("?")+1, URL.Length()-URL.Find("?")-1);

		// search the fieldname beginning / middle and strip the rest...
		if (Parameter.Find(fieldname + "=") == 0) {
			findPos = 0;
			findLength = fieldname.Length() + 1;
		}
		if (Parameter.Find("&" + fieldname + "=") > -1) {
			findPos = Parameter.Find("&" + fieldname + "=");
			findLength = fieldname.Length() + 2;
		}
		if (findPos > -1) {
			Parameter = Parameter.Mid(findPos + findLength, Parameter.Length());
			if (Parameter.Find("&") > -1) {
				Parameter = Parameter.Mid(0, Parameter.Find("&"));
			}
	
			value = Parameter;

			// decode value ...
			value.Replace("+", " ");
			for (i = 0 ; i <= 255 ; i++) {
				sprintf(fromReplace, "%%%02x", i);
				toReplace[0] = (char)i;
				toReplace[1] = 0;
				value.Replace(fromReplace, toReplace);
				sprintf(fromReplace, "%%%02X", i);
				value.Replace(fromReplace, toReplace);
			}
		}
	}
	printf("*** URL parsed. returning %s\n",value.GetData());
	return value;
}

wxString CWebServer::_GetHeader(ThreadData Data, long lSession)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession; sSession.Printf("%ld", lSession);

	wxString Out = pThis->m_Templates.sHeader;

	Out.Replace("[CharSet]", _GetWebCharSet());

	if(theApp.glob_prefs->GetWebPageRefresh() != 0)
	{
		wxString sPage = _ParseURL(Data.sURL, "w");
		if ((sPage == "transfer") ||
			(sPage == "server") ||
			(sPage == "graphs") ||
			(sPage == "log") ||
			(sPage == "sinfo") ||
			(sPage == "debuglog") ||
			(sPage == "stats"))
		{
			wxString sT = pThis->m_Templates.sHeaderMetaRefresh;
			wxString sRefresh; sRefresh.Printf("%d", theApp.glob_prefs->GetWebPageRefresh());
			sT.Replace("[RefreshVal]", sRefresh);
			sT.Replace("[wCommand]", _ParseURL(Data.sURL, "w"));
			Out.Replace("[HeaderMeta]", sT);
		}
	}
	Out.Replace("[Session]", sSession);
	printf("*** replaced session with %s\n",sSession.GetData());
	Out.Replace("[HeaderMeta]", ""); // In case there are no meta
	Out.Replace("[eMuleAppName]", "eMule");
	Out.Replace("[version]", CURRENT_VERSION_LONG);
	Out.Replace("[StyleSheet]", pThis->m_Templates.sHeaderStylesheet);
	Out.Replace("[WebControl]", _GetPlainResString(IDS_WEB_CONTROL));
	Out.Replace("[Transfer]", _GetPlainResString(IDS_CD_TRANS));
	Out.Replace("[Server]", _GetPlainResString(IDS_SV_SERVERLIST));
	Out.Replace("[Shared]", _GetPlainResString(IDS_SHAREDFILES));
	Out.Replace("[Download]", _GetPlainResString(IDS_SW_LINK));
	Out.Replace("[Graphs]", _GetPlainResString(IDS_GRAPHS));
	Out.Replace("[Log]", _GetPlainResString(IDS_SV_LOG));
	Out.Replace("[ServerInfo]", _GetPlainResString(IDS_SV_SERVERINFO));
	Out.Replace("[DebugLog]", _GetPlainResString(IDS_SV_DEBUGLOG));
	Out.Replace("[Stats]", _GetPlainResString(IDS_SF_STATISTICS));
	Out.Replace("[Options]", _GetPlainResString(IDS_EM_PREFS));
	Out.Replace("[Logout]", _GetPlainResString(IDS_WEB_LOGOUT));
	char HTTPTempC[100] = "";
	wxString sConnected = "";
	if (theApp.serverconnect->IsConnected()) 
	{
		if(!theApp.serverconnect->IsLowID())
			sConnected = _GetPlainResString(IDS_CONNECTED);
		else
			sConnected = _GetPlainResString(IDS_CONNECTED) + " (" + _GetPlainResString(IDS_IDLOW) + ")";

		CServer* cur_server = theApp.serverconnect->GetCurrentServer();
		sConnected += ": " + wxString(cur_server->GetListName());

		sprintf(HTTPTempC, "%i ", cur_server->GetUsers());
		sConnected += " [" + wxString(HTTPTempC) + _GetPlainResString(IDS_LUSERS) + "]";

	} 
	else if (theApp.serverconnect->IsConnecting())
	{
		sConnected = _GetPlainResString(IDS_CONNECTING);
	}
	else
	{
		sConnected = _GetPlainResString(IDS_DISCONNECTED);
		if (IsSessionAdmin(Data,sSession)) sConnected+=" (<small><a href=\"/?ses=" + sSession + "&w=server&c=connect\">"+_GetPlainResString(IDS_CONNECTTOANYSERVER)+"</a></small>)";
	}
	Out.Replace("[Connected]", "<b>"+_GetPlainResString(IDS_PW_CONNECTION)+":</b> "+sConnected);
    sprintf(HTTPTempC, _GetPlainResString(IDS_UPDOWNSMALL),(float)theApp.uploadqueue->GetDatarate()/1024,(float)theApp.downloadqueue->GetDatarate()/1024);
	wxString sLimits;
	// EC 25-12-2003
	wxString MaxUpload;
	wxString MaxDownload;
	MaxUpload.Printf("%i",theApp.glob_prefs->GetMaxUpload());
	MaxDownload.Printf("%i",theApp.glob_prefs->GetMaxDownload());
	if (MaxUpload == "65535")  MaxUpload = GetResString(IDS_PW_UNLIMITED);
	if (MaxDownload == "65535") MaxDownload = GetResString(IDS_PW_UNLIMITED);
	sLimits.Printf("%s/%s", MaxUpload.GetData(), MaxDownload.GetData());
	// EC Ends
	Out.Replace("[Speed]", "<b>"+_GetPlainResString(IDS_DL_SPEED)+":</b> "+wxString(HTTPTempC) + "<small> (" + _GetPlainResString(IDS_PW_CON_LIMITFRM) + ": " + sLimits + ")</small>");

	return Out;
}

wxString CWebServer::_GetFooter(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	return pThis->m_Templates.sFooter;
}

wxString CWebServer::_GetServerList(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession = _ParseURL(Data.sURL, "ses");

	wxString sAddServerBox = "";

	wxString sCmd = _ParseURL(Data.sURL, "c");
	if (sCmd == "connect" && IsSessionAdmin(Data,sSession) )
	{
		wxString sIP = _ParseURL(Data.sURL, "ip");
		if(sIP.IsEmpty()) {
			//theApp.emuledlg->SendMessage(WM_COMMAND, MP_CONNECT);
			wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED,MP_CONNECT);
			wxPostEvent(theApp.emuledlg,evt);
		} else
			_ConnectToServer(sIP);
	}	
	else if (sCmd == "disconnect" && IsSessionAdmin(Data,sSession)) 
	{
		//theApp.emuledlg->SendMessage(WM_COMMAND, MP_DISCONNECT);
		wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED,MP_DISCONNECT);
		wxPostEvent(theApp.emuledlg,evt);
	}	
	else if (sCmd == "remove" && IsSessionAdmin(Data,sSession)) 
	{
		wxString sIP = _ParseURL(Data.sURL, "ip");
		if(!sIP.IsEmpty())
			_RemoveServer(sIP);
	}	
	else if (sCmd == "options") 
	{
		sAddServerBox = _GetAddServerBox(Data);
	}
	wxString sSort = _ParseURL(Data.sURL, "sort");
	if (sSort != "") 
	{
		if(sSort == "name")
			pThis->m_Params.ServerSort = SERVER_SORT_NAME;
		else
		if(sSort == "description")
			pThis->m_Params.ServerSort = SERVER_SORT_DESCRIPTION;
		else
		if(sSort == "ip")
			pThis->m_Params.ServerSort = SERVER_SORT_IP;
		else
		if(sSort == "users")
			pThis->m_Params.ServerSort = SERVER_SORT_USERS;
		else
		if(sSort == "files")
			pThis->m_Params.ServerSort = SERVER_SORT_FILES;

		if(_ParseURL(Data.sURL, "sortreverse") == "")
			pThis->m_Params.bServerSortReverse = false;
	}
	if (_ParseURL(Data.sURL, "sortreverse") != "") 
	{
		pThis->m_Params.bServerSortReverse = (_ParseURL(Data.sURL, "sortreverse") == "true");
	}
	wxString sServerSortRev;
	if(pThis->m_Params.bServerSortReverse)
		sServerSortRev = "false";
	else
		sServerSortRev = "true";

	wxString Out = pThis->m_Templates.sServerList;
	Out.Replace("[ConnectedServerData]", _GetConnectedServer(Data));
    Out.Replace("[AddServerBox]", sAddServerBox);
	Out.Replace("[Session]", sSession);
	if(pThis->m_Params.ServerSort == SERVER_SORT_NAME)
		Out.Replace("[SortName]", "&sortreverse=" + sServerSortRev);
	else
		Out.Replace("[SortName]", "");
	if(pThis->m_Params.ServerSort == SERVER_SORT_DESCRIPTION)
		Out.Replace("[SortDescription]", "&sortreverse=" + sServerSortRev);
	else
		Out.Replace("[SortDescription]", "");
	if(pThis->m_Params.ServerSort == SERVER_SORT_IP)
		Out.Replace("[SortIP]", "&sortreverse=" + sServerSortRev);
	else
		Out.Replace("[SortIP]", "");
	if(pThis->m_Params.ServerSort == SERVER_SORT_USERS)
		Out.Replace("[SortUsers]", "&sortreverse=" + sServerSortRev);
	else
		Out.Replace("[SortUsers]", "");
	if(pThis->m_Params.ServerSort == SERVER_SORT_FILES)
		Out.Replace("[SortFiles]", "&sortreverse=" + sServerSortRev);
	else
		Out.Replace("[SortFiles]", "");
	Out.Replace("[ServerList]", _GetPlainResString(IDS_SV_SERVERLIST));
	Out.Replace("[Servername]", _GetPlainResString(IDS_SL_SERVERNAME));
	Out.Replace("[Description]", _GetPlainResString(IDS_DESCRIPTION));
	Out.Replace("[Address]", _GetPlainResString(IDS_IP));
	Out.Replace("[Connect]", _GetPlainResString(IDS_IRC_CONNECT));
	Out.Replace("[Users]", _GetPlainResString(IDS_LUSERS));
	Out.Replace("[Files]", _GetPlainResString(IDS_LFILES));
	//Out.Replace("[Actions]", _GetPlainResString(IDS_WEB_ACTIONS));
		
	wxString OutE = pThis->m_Templates.sServerLine;
	OutE.Replace("[Connect]", _GetPlainResString(IDS_IRC_CONNECT));
	OutE.Replace("[RemoveServer]", _GetPlainResString(IDS_REMOVETHIS));
	//OutE.Replace("[ConfirmRemove]", _GetPlainResString(IDS_WEB_CONFIRM_REMOVE_SERVER));

	CArray<ServerEntry*, ServerEntry*> ServerArray;

	// Populating array
	for (uint32 sc=0;sc<theApp.serverlist->GetServerCount();sc++)
	{
		CServer* cur_file = theApp.serverlist->GetServerAt(sc);
		ServerEntry* Entry=new ServerEntry;
		Entry->sServerName = _SpecialChars(cur_file->GetListName());
		Entry->sServerDescription = _SpecialChars(cur_file->GetDescription());
		Entry->nServerPort = cur_file->GetPort();
		Entry->sServerIP = cur_file->GetAddress();
		Entry->nServerUsers = cur_file->GetUsers();
		Entry->nServerMaxUsers = cur_file->GetMaxUsers();
		Entry->nServerFiles = cur_file->GetFiles();
	
		ServerArray.Add(Entry);
	}
	// Sorting (simple bubble sort, we don't have tons of data here)
	bool bSorted = true;
	for(int nMax = 0;bSorted && nMax < ServerArray.GetCount()*2; nMax++)
	{
		bSorted = false;
		for(int i = 0; i < ServerArray.GetCount() - 1; i++)
		{
			bool bSwap = false;
			switch(pThis->m_Params.ServerSort)
			{
			case SERVER_SORT_NAME:
				bSwap = ServerArray[i]->sServerName.CmpNoCase(ServerArray[i+1]->sServerName) > 0;
				break;
			case SERVER_SORT_DESCRIPTION:
				bSwap = ServerArray[i]->sServerDescription.CmpNoCase(ServerArray[i+1]->sServerDescription) < 0;
				break;
			case SERVER_SORT_IP:
				bSwap = ServerArray[i]->sServerIP.CmpNoCase(ServerArray[i+1]->sServerIP) > 0;
				break;
			case SERVER_SORT_USERS:
				bSwap = ServerArray[i]->nServerUsers < ServerArray[i+1]->nServerUsers;
				break;
			case SERVER_SORT_FILES:
				bSwap = ServerArray[i]->nServerFiles < ServerArray[i+1]->nServerFiles;
				break;
			}
			if(pThis->m_Params.bServerSortReverse)
			{
				bSwap = !bSwap;
			}
			if(bSwap)
			{
				bSorted = true;
				ServerEntry* TmpEntry = ServerArray[i];
				ServerArray[i] = ServerArray[i+1];
				ServerArray[i+1] = TmpEntry;
			}
		}
	}
	// Displaying
	wxString sList = "";
	for(int i = 0; i < ServerArray.GetCount(); i++)
	{
		wxString HTTPProcessData = OutE;	// Copy Entry Line to Temp
		HTTPProcessData.Replace("[1]", ServerArray[i]->sServerName);
		HTTPProcessData.Replace("[2]", ServerArray[i]->sServerDescription);
		wxString sPort; sPort.Printf(":%d", ServerArray[i]->nServerPort);
		HTTPProcessData.Replace("[3]", ServerArray[i]->sServerIP + sPort);
		wxString sT;
		if(ServerArray[i]->nServerUsers > 0)
		{
			if(ServerArray[i]->nServerMaxUsers > 0)
				sT.Printf("%d (%d)", ServerArray[i]->nServerUsers, ServerArray[i]->nServerMaxUsers);
			else
				sT.Printf("%d", ServerArray[i]->nServerUsers);
		}
		HTTPProcessData.Replace("[4]", sT);
		sT = "";
		if(ServerArray[i]->nServerFiles > 0)
			sT.Printf("%d", ServerArray[i]->nServerFiles);
		HTTPProcessData.Replace("[5]", sT);
		HTTPProcessData.Replace("[6]", IsSessionAdmin(Data,sSession)? wxString("/?ses=" + sSession + "&w=server&c=connect&ip=" + ServerArray[i]->sServerIP):GetPermissionDenied());
		HTTPProcessData.Replace("[LinkRemove]", IsSessionAdmin(Data,sSession)?wxString("/?ses=" + sSession + "&w=server&c=remove&ip=" + ServerArray[i]->sServerIP):GetPermissionDenied());

		sList += HTTPProcessData;
	}
	Out.Replace("[ServersList]", sList);

	return Out;
}

wxString CWebServer::_GetTransferList(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession = _ParseURL(Data.sURL, "ses");

	wxString Out = "";
	if (_ParseURL(Data.sURL, "c") != "" && IsSessionAdmin(Data,sSession)) 
	{
		wxString HTTPTemp = _ParseURL(Data.sURL, "c");
		if (HTTPTemp.Right(1) != "/")
			HTTPTemp += "/";
		try 
		{
			CED2KLink* pLink = CED2KLink::CreateLinkFromUrl(HTTPTemp);
			if (pLink->GetKind() == CED2KLink::kFile)
				theApp.downloadqueue->AddFileLinkToDownload(pLink->GetFileLink());
			else
				throw wxString("bad link");
			delete pLink;
		}
		catch(wxString error)
		{
			char HTTPTempC[100] = "";
			sprintf(HTTPTempC,_GetPlainResString(IDS_ERR_INVALIDLINK),error.GetData());
			Out += pThis->m_Templates.sTransferBadLink;
			Out.Replace("[InvalidLink]", HTTPTempC);
			Out.Replace("[Link]", HTTPTemp);
		}
	}
	if (_ParseURL(Data.sURL, "op") != "" &&
		_ParseURL(Data.sURL, "file") != "")
	{
		uchar FileHash[16];
		_GetFileHash(_ParseURL(Data.sURL, "file"), FileHash);

		CPartFile* found_file = NULL;

		for (int fx=0;fx<theApp.downloadqueue->GetFileCount();fx++)
		{			
			CPartFile* cur_file =  theApp.downloadqueue->GetFileByIndex(fx);

			bool bGood = true;
			for(int i = 0; i < 16; i++)
			{
				if(cur_file->GetFileHash()[i] != FileHash[i])
				{
					bGood = false;
					break;
				}
			}
			if(bGood)
			{
				found_file = cur_file;
				break;
			}
		}

		if(_ParseURL(Data.sURL, "op") == "pause" && IsSessionAdmin(Data,sSession))
		{
			if(found_file)
				found_file->PauseFile();
		}
		else if(_ParseURL(Data.sURL, "op") == "resume" && IsSessionAdmin(Data,sSession))
		{
			if(found_file)
				found_file->ResumeFile();
		}
		else if(_ParseURL(Data.sURL, "op") == "cancel" && IsSessionAdmin(Data,sSession))
		{
			if(found_file)
				found_file->DeleteFile();
		}
	}
	if (_ParseURL(Data.sURL, "sort") != "") 
	{
		if(_ParseURL(Data.sURL, "sort") == "name")
			pThis->m_Params.DownloadSort = DOWN_SORT_NAME;
		else
		if(_ParseURL(Data.sURL, "sort") == "size")
			pThis->m_Params.DownloadSort = DOWN_SORT_SIZE;
		else
		if(_ParseURL(Data.sURL, "sort") == "transferred")
			pThis->m_Params.DownloadSort = DOWN_SORT_TRANSFERRED;
		else
		if(_ParseURL(Data.sURL, "sort") == "speed")
			pThis->m_Params.DownloadSort = DOWN_SORT_SPEED;
		else
		if(_ParseURL(Data.sURL, "sort") == "progress")
			pThis->m_Params.DownloadSort = DOWN_SORT_PROGRESS;

		if(_ParseURL(Data.sURL, "sortreverse") == "")
			pThis->m_Params.bDownloadSortReverse = false;
	}
	if (_ParseURL(Data.sURL, "sortreverse") != "") 
	{
		pThis->m_Params.bDownloadSortReverse = (_ParseURL(Data.sURL, "sortreverse") == "true");
	}
	if(_ParseURL(Data.sURL, "showuploadqueue") == "true")
	{
		pThis->m_Params.bShowUploadQueue = true;
	}
	if(_ParseURL(Data.sURL, "showuploadqueue") == "false")
	{
		pThis->m_Params.bShowUploadQueue = false;
	}
	wxString sDownloadSortRev;
	if(pThis->m_Params.bDownloadSortReverse)
		sDownloadSortRev = "false";
	else
		sDownloadSortRev = "true";

	Out += pThis->m_Templates.sTransferImages;
	Out += pThis->m_Templates.sTransferList;
	Out.Replace("[DownloadHeader]", pThis->m_Templates.sTransferDownHeader);
	Out.Replace("[DownloadFooter]", pThis->m_Templates.sTransferDownFooter);
	Out.Replace("[UploadHeader]", pThis->m_Templates.sTransferUpHeader);
	Out.Replace("[UploadFooter]", pThis->m_Templates.sTransferUpFooter);
	Out.Replace("[Session]", sSession);
	if(pThis->m_Params.DownloadSort == DOWN_SORT_NAME)
		Out.Replace("[SortName]", "&sortreverse=" + sDownloadSortRev);
	else
		Out.Replace("[SortName]", "");
	if(pThis->m_Params.DownloadSort == DOWN_SORT_SIZE)
		Out.Replace("[SortSize]", "&sortreverse=" + sDownloadSortRev);
	else
		Out.Replace("[SortSize]", "");
	if(pThis->m_Params.DownloadSort == DOWN_SORT_TRANSFERRED)
		Out.Replace("[SortTransferred]", "&sortreverse=" + sDownloadSortRev);
	else
		Out.Replace("[SortTransferred]", "");
	if(pThis->m_Params.DownloadSort == DOWN_SORT_SPEED)
		Out.Replace("[SortSpeed]", "&sortreverse=" + sDownloadSortRev);
	else
		Out.Replace("[SortSpeed]", "");
	if(pThis->m_Params.DownloadSort == DOWN_SORT_PROGRESS)
		Out.Replace("[SortProgress]", "&sortreverse=" + sDownloadSortRev);
	else
		Out.Replace("[SortProgress]", "");

	Out.Replace("[DownloadList]", _GetPlainResString(IDS_TW_DOWNLOADS));
	Out.Replace("[Filename]", _GetPlainResString(IDS_DL_FILENAME));
	Out.Replace("[Size]", _GetPlainResString(IDS_DL_SIZE));
	Out.Replace("[Transferred]", _GetPlainResString(IDS_DL_TRANSF));
	Out.Replace("[Progress]", _GetPlainResString(IDS_DL_PROGRESS));
	Out.Replace("[Speed]", _GetPlainResString(IDS_DL_SPEED));
	Out.Replace("[Sources]", _GetPlainResString(IDS_DL_SOURCES));
	Out.Replace("[Actions]", _GetPlainResString(IDS_WEB_ACTIONS));
	Out.Replace("[UploadList]", _GetPlainResString(IDS_PW_CON_UPLBL));
	Out.Replace("[User]", _GetPlainResString(IDS_QL_USERNAME));
	Out.Replace("[TotalDown]", _GetPlainResString(IDS_INFLST_USER_TOTALDOWNLOAD));
	Out.Replace("[TotalUp]", _GetPlainResString(IDS_INFLST_USER_TOTALUPLOAD));

	wxString OutE = pThis->m_Templates.sTransferDownLine;
	wxString OutE2 = pThis->m_Templates.sTransferDownLineGood;

	float fTotalSize = 0, fTotalTransferred = 0, fTotalSpeed = 0;
	CArray<DownloadFiles*, DownloadFiles*> FilesArray;
	// Populating array

	for (int fx=0;fx<theApp.downloadqueue->GetFileCount();fx++)
	{
		CPartFile* cur_file =  theApp.downloadqueue->GetFileByIndex(fx);

		DownloadFiles* dFile=new DownloadFiles;
		dFile->sFileName = _SpecialChars(cur_file->GetFileName());
		dFile->lFileSize = cur_file->GetFileSize();
		dFile->lFileTransferred = cur_file->GetTransfered();
		dFile->lFileSpeed = cur_file->GetDatarate();
		dFile->nFileStatus = cur_file->GetStatus();
		dFile->sFileStatus = cur_file->getPartfileStatus();
		dFile->sFileHash = EncodeBase16(cur_file->GetFileHash(), 16);
		dFile->lSourceCount = cur_file->GetSourceCount();
		dFile->lNotCurrentSourceCount = cur_file->GetNotCurrentSourcesCount();
		dFile->lTransferringSourceCount = cur_file->GetTransferingSrcCount();
		if (theApp.serverconnect->IsConnected() && !theApp.serverconnect->IsLowID())
			dFile->sED2kLink = theApp.CreateED2kSourceLink(cur_file);
		else
		  dFile->sED2kLink = theApp.CreateED2kLink(cur_file);
		dFile->sFileInfo = _SpecialChars(cur_file->GetDownloadFileInfo());

		FilesArray.Add(dFile);
	}

	// Sorting (simple bubble sort, we don't have tons of data here)
	bool bSorted = true;
	for(int nMax = 0;bSorted && nMax < FilesArray.GetCount()*2; nMax++)
	{
		bSorted = false;
		for(int i = 0; i < FilesArray.GetCount() - 1; i++)
		{
			bool bSwap = false;
			switch(pThis->m_Params.DownloadSort)
			{
			case DOWN_SORT_NAME:
				bSwap = FilesArray[i]->sFileName.CmpNoCase(FilesArray[i+1]->sFileName) > 0;
				break;
			case DOWN_SORT_SIZE:
				bSwap = FilesArray[i]->lFileSize < FilesArray[i+1]->lFileSize;
				break;
			case DOWN_SORT_TRANSFERRED:
				bSwap = FilesArray[i]->lFileTransferred < FilesArray[i+1]->lFileTransferred;
				break;
			case DOWN_SORT_SPEED:
				bSwap = FilesArray[i]->lFileSpeed < FilesArray[i+1]->lFileSpeed;
				break;
			case DOWN_SORT_PROGRESS:
				{
					int nPercent1 = 0, nPercent2 = 0;
					if(FilesArray[i]->lFileSize > 0)
					{
						float fS = FilesArray[i]->lFileSize, fT = FilesArray[i]->lFileTransferred;
						nPercent1 = abs((int)((fT * 100.0) / fS));
					}
					if(FilesArray[i+1]->lFileSize > 0)
					{
						float fS = FilesArray[i+1]->lFileSize, fT = FilesArray[i+1]->lFileTransferred;
						nPercent2 = abs((int)((fT * 100.0) / fS));
					}
					bSwap = nPercent1 < nPercent2;
				}
			}
			if(pThis->m_Params.bDownloadSortReverse)
			{
				bSwap = !bSwap;
			}
			if(bSwap)
			{
				bSorted = true;
				DownloadFiles* TmpFile = FilesArray[i];
				FilesArray[i] = FilesArray[i+1];
				FilesArray[i+1] = TmpFile;
			}
		}
	}

	// Displaying
	wxString sDownList = "";
	wxString HTTPTemp;

	for(int i = 0; i < FilesArray.GetCount(); i++)
	{
		wxString JSfileinfo=FilesArray[i]->sFileInfo;
		JSfileinfo.Replace("\n","\\n");
		wxString sActions = "<acronym title=\"" + FilesArray[i]->sFileStatus + "\"><a href=\"javascript:alert(\'"+ JSfileinfo+"')\"><img src=\"javascript:img_info\" alt=\"" + FilesArray[i]->sFileStatus + "\"></a></acronym> ";

		wxString sED2kLink;
		sED2kLink.Printf("<acronym title=\"[Ed2klink]\"><a href=\""+ FilesArray[i]->sED2kLink +"\"><img src=\"javascript:img_link\" alt=\"[Ed2klink]\"></a></acronym> ");
		sED2kLink.Replace("[Ed2klink]", _GetPlainResString(IDS_SW_LINK));
		sActions += sED2kLink;

		bool bCanBeDeleted = true;
		switch(FilesArray[i]->nFileStatus)
		{
		case PS_COMPLETING:
		case PS_COMPLETE:
			bCanBeDeleted = false;
			break;
		case PS_HASHING: 
		case PS_WAITINGFORHASH:
		case PS_ERROR:
			break;
		case PS_PAUSED:
		{
			wxString sResume;
			sResume.Printf("<acronym title=\"[Resume]\"><a href=\"[Link]\"><img src=\"javascript:img_resume\" alt=\"[Resume]\"></a></acronym> ");
			
			sResume.Replace("[Link]", IsSessionAdmin(Data,sSession)?wxString("/?ses=" + sSession + "&w=transfer&op=resume&file=" + FilesArray[i]->sFileHash):GetPermissionDenied()) ;
			
			sActions += sResume;
		}
			break; 
		default: // waiting or downloading
		{
			wxString sPause;
			sPause.Printf("<acronym title=\"[Pause]\"><a href=\"[Link]\"><img src=\"javascript:img_pause\" alt=\"[Pause]\"></a></acronym> ");
			sPause.Replace("[Link]", IsSessionAdmin(Data,sSession)?wxString("/?ses=" + sSession + "&w=transfer&op=pause&file=" + FilesArray[i]->sFileHash):GetPermissionDenied());
			sActions += sPause;
		}
			break;
		}
		if(bCanBeDeleted)
		{
			wxString sCancel;
			sCancel.Printf("<acronym title=\"[Cancel]\"><a href=\"[Link]\" onclick=\"return confirm(\'[ConfirmCancel]\')\"><img src=\"javascript:img_cancel\" alt=\"[Cancel]\"></a></acronym> ");
			sCancel.Replace("[Link]", IsSessionAdmin(Data,sSession)?wxString("/?ses=" + sSession + "&w=transfer&op=cancel&file=" + FilesArray[i]->sFileHash):GetPermissionDenied());
			sActions += sCancel;
		}
		sActions.Replace("[Resume]", _GetPlainResString(IDS_DL_RESUME));
		sActions.Replace("[Pause]", _GetPlainResString(IDS_DL_PAUSE));
		sActions.Replace("[Cancel]", _GetPlainResString(IDS_MAIN_BTN_CANCEL));
		sActions.Replace("[ConfirmCancel]", _GetPlainResString(IDS_Q_CANCELDL2, true));

		wxString HTTPProcessData;
		// if downloading, draw in other color
		if(FilesArray[i]->lFileSpeed > 0)
			HTTPProcessData = OutE2;
		else
			HTTPProcessData = OutE;

		if(FilesArray[i]->sFileName.Length() > SHORT_FILENAME_LENGTH)
			HTTPProcessData.Replace("[ShortFileName]", FilesArray[i]->sFileName.Left(SHORT_FILENAME_LENGTH) + "...");
		else
			HTTPProcessData.Replace("[ShortFileName]", FilesArray[i]->sFileName);

		HTTPProcessData.Replace("[FileInfo]", FilesArray[i]->sFileInfo);

		fTotalSize += FilesArray[i]->lFileSize;

		HTTPProcessData.Replace("[2]", CastItoXBytes(FilesArray[i]->lFileSize));

		if(FilesArray[i]->lFileTransferred > 0)
		{
			fTotalTransferred += FilesArray[i]->lFileTransferred;

			HTTPProcessData.Replace("[3]", CastItoXBytes(FilesArray[i]->lFileTransferred));
		}
		else
			HTTPProcessData.Replace("[3]", "-");

		HTTPProcessData.Replace("[DownloadBar]", _GetDownloadGraph(Data,FilesArray[i]->sFileHash));

		if(FilesArray[i]->lFileSpeed > 0.0f)
		{
			fTotalSpeed += FilesArray[i]->lFileSpeed;

			HTTPTemp.Printf("%8.2f %s", FilesArray[i]->lFileSpeed/1024.0 ,_GetPlainResString(IDS_KBYTESEC).GetData() );
			HTTPProcessData.Replace("[4]", HTTPTemp);
		}
		else
			HTTPProcessData.Replace("[4]", "-");
		if(FilesArray[i]->lSourceCount > 0)
		{
			HTTPTemp.Printf("%8i/%8i (%i)",
				FilesArray[i]->lSourceCount-FilesArray[i]->lNotCurrentSourceCount,
				FilesArray[i]->lSourceCount,
				FilesArray[i]->lTransferringSourceCount);

		HTTPProcessData.Replace("[5]", HTTPTemp);
		}
		else
			HTTPProcessData.Replace("[5]", "-");

		HTTPProcessData.Replace("[6]", sActions);

		sDownList += HTTPProcessData;
	}

	// clear the array
	for(int qq=0;qq<FilesArray.GetCount();qq++) {
	  delete FilesArray[qq];
	}

	Out.Replace("[DownloadFilesList]", sDownList);
	
	Out.Replace("[TotalDownSize]", CastItoXBytes((long long)fTotalSize));

	Out.Replace("[TotalDownTransferred]", CastItoXBytes((long long)fTotalTransferred));
	
	HTTPTemp.Printf("%8.2f %s", fTotalSpeed/1024.0,_GetPlainResString(IDS_KBYTESEC).GetData());
	Out.Replace("[TotalDownSpeed]", HTTPTemp);
	OutE = pThis->m_Templates.sTransferUpLine;
	
	HTTPTemp.Printf("%i",pThis->m_Templates.iProgressbarWidth);
	Out.Replace("[PROGRESSBARWIDTHVAL]",HTTPTemp);

	fTotalSize = 0;
	fTotalTransferred = 0;
	fTotalSpeed = 0;

	wxString sUpList = "";
	
	for (POSITION pos = theApp.uploadqueue->GetFirstFromUploadList();
		pos != 0;theApp.uploadqueue->GetNextFromUploadList(pos))
	{
		CUpDownClient* cur_client = theApp.uploadqueue->GetQueueClientAt(pos);
		wxString HTTPProcessData = OutE;
		HTTPProcessData.Replace("[1]", _SpecialChars(cur_client->GetUserName()));
		HTTPProcessData.Replace("[FileInfo]", _SpecialChars(cur_client->GetUploadFileInfo()));

#warning this will need totally new PartFile and Knownfile to work
#if 0
		CKnownFile* file = theApp.sharedfiles->GetFileByID(cur_client->GetUploadFileID());
		if (file)
			HTTPProcessData.Replace("[2]", _SpecialChars(wxString(file->GetFileName())));
		else
			HTTPProcessData.Replace("[2]", _GetPlainResString(IDS_REQ_UNKNOWNFILE));
#endif

		fTotalSize += cur_client->GetTransferedDown();
		fTotalTransferred += cur_client->GetTransferedUp();
		wxString HTTPTemp;
		HTTPTemp.Printf("%s / %s", CastItoXBytes(cur_client->GetTransferedDown()).GetData(),CastItoXBytes(cur_client->GetTransferedUp()).GetData());
		HTTPProcessData.Replace("[3]", HTTPTemp);

		fTotalSpeed += cur_client->GetDatarate();
		HTTPTemp.Printf("%8.2f " + _GetPlainResString(IDS_KBYTESEC), cur_client->GetDatarate()/1024.0);
		HTTPProcessData.Replace("[4]", HTTPTemp);
		sUpList += HTTPProcessData;
	}

	Out.Replace("[UploadFilesList]", sUpList);
	HTTPTemp.Printf("%s / %s", CastItoXBytes((long long)fTotalSize).GetData(), CastItoXBytes((long long)fTotalTransferred).GetData());
	Out.Replace("[TotalUpTransferred]", HTTPTemp);
	HTTPTemp.Printf("%8.2f " + _GetPlainResString(IDS_KBYTESEC), fTotalSpeed/1024.0);
	Out.Replace("[TotalUpSpeed]", HTTPTemp);

	if(pThis->m_Params.bShowUploadQueue) 
	{
		Out.Replace("[UploadQueue]", pThis->m_Templates.sTransferUpQueueShow);
		Out.Replace("[UploadQueueList]", _GetPlainResString(IDS_ONQUEUE));
		Out.Replace("[UserNameTitle]", _GetPlainResString(IDS_QL_USERNAME));
		Out.Replace("[FileNameTitle]", _GetPlainResString(IDS_DL_FILENAME));
		Out.Replace("[ScoreTitle]", _GetPlainResString(IDS_SCORE));
		Out.Replace("[BannedTitle]", _GetPlainResString(IDS_BANNED));

		OutE = pThis->m_Templates.sTransferUpQueueLine;
		// Replace [xx]
		wxString sQueue = "";

		for (POSITION pos = theApp.uploadqueue->GetFirstFromWaitingList(); pos != 0;theApp.uploadqueue->GetNextFromWaitingList(pos)){
			CUpDownClient* cur_client = theApp.uploadqueue->GetWaitClientAt(pos);
			wxString HTTPProcessData;
            char HTTPTempC[100] = "";
			HTTPProcessData = OutE;
			HTTPProcessData.Replace("[UserName]", _SpecialChars(cur_client->GetUserName()));
			if (cur_client->reqfile)
				HTTPProcessData.Replace("[FileName]", _SpecialChars(cur_client->reqfile->GetFileName()));
			else
				HTTPProcessData.Replace("[FileName]", "?");
			sprintf(HTTPTempC, "%i" , cur_client->GetScore(false));
			wxString HTTPTemp = HTTPTempC;
			HTTPProcessData.Replace("[Score]", HTTPTemp);
			if (cur_client->IsBanned())
				HTTPProcessData.Replace("[Banned]", _GetPlainResString(IDS_YES));
			else
				HTTPProcessData.Replace("[Banned]", _GetPlainResString(IDS_NO));
			sQueue += HTTPProcessData;
		}
		Out.Replace("[QueueList]", sQueue);
	}
	else {
		Out.Replace("[UploadQueue]", pThis->m_Templates.sTransferUpQueueHide);
	}
	Out.Replace("[ShowQueue]", _GetPlainResString(IDS_WEB_SHOW_UPLOAD_QUEUE));
	Out.Replace("[HideQueue]", _GetPlainResString(IDS_WEB_HIDE_UPLOAD_QUEUE));
	Out.Replace("[Session]", sSession);

	return Out;
}

wxString CWebServer::_GetDownloadLink(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession = _ParseURL(Data.sURL, "ses");

	if (!IsSessionAdmin(Data,sSession)) return "";
	wxString Out = pThis->m_Templates.sDownloadLink;

	Out.Replace("[Download]", _GetPlainResString(IDS_SW_DOWNLOAD));
	Out.Replace("[Ed2klink]", _GetPlainResString(IDS_SW_LINK));
	Out.Replace("[Start]", _GetPlainResString(IDS_SW_START));
	Out.Replace("[Session]", sSession);

	return Out;
}

wxString CWebServer::_GetSharedFilesList(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
        wxString sSession = _ParseURL(Data.sURL, "ses");
	if(pThis == NULL)
		return "";
	if (_ParseURL(Data.sURL, "sort") != "") 
	{
		if(_ParseURL(Data.sURL, "sort") == "name")
			pThis->m_Params.SharedSort = SHARED_SORT_NAME;
		else
		if(_ParseURL(Data.sURL, "sort") == "size")
			pThis->m_Params.SharedSort = SHARED_SORT_SIZE;
		else
		if(_ParseURL(Data.sURL, "sort") == "transferred")
			pThis->m_Params.SharedSort = SHARED_SORT_TRANSFERRED;
		else
		if(_ParseURL(Data.sURL, "sort") == "alltimetransferred")
			pThis->m_Params.SharedSort = SHARED_SORT_ALL_TIME_TRANSFERRED;
		else
		if(_ParseURL(Data.sURL, "sort") == "requests")
			pThis->m_Params.SharedSort = SHARED_SORT_REQUESTS;
		else
		if(_ParseURL(Data.sURL, "sort") == "alltimerequests")
			pThis->m_Params.SharedSort = SHARED_SORT_ALL_TIME_REQUESTS;
		else
		if(_ParseURL(Data.sURL, "sort") == "accepts")
			pThis->m_Params.SharedSort = SHARED_SORT_ACCEPTS;
		else
		if(_ParseURL(Data.sURL, "sort") == "alltimeaccepts")
			pThis->m_Params.SharedSort = SHARED_SORT_ALL_TIME_ACCEPTS;
		else
		if(_ParseURL(Data.sURL, "sort") == "priority")
			pThis->m_Params.SharedSort = SHARED_SORT_PRIORITY;

		if(_ParseURL(Data.sURL, "sortreverse") == "")
			pThis->m_Params.bSharedSortReverse = false;
	}
	if (_ParseURL(Data.sURL, "sortreverse") != "") 
		pThis->m_Params.bSharedSortReverse = (_ParseURL(Data.sURL, "sortreverse") == "true");

	if(_ParseURL(Data.sURL, "hash") != "" && _ParseURL(Data.sURL, "setpriority") != "" && IsSessionAdmin(Data,sSession)) 
		_SetSharedFilePriority(_ParseURL(Data.sURL, "hash"),atoi(_ParseURL(Data.sURL, "setpriority")));

	if(_ParseURL(Data.sURL, "reload") == "true")
	{
	  //theApp.emuledlg->SendMessage(WEB_SHARED_FILES_RELOAD);
#warning wxPostEvent here
	}

	wxString sSharedSortRev;
	if(pThis->m_Params.bSharedSortReverse)
		sSharedSortRev = "false";
	else
		sSharedSortRev = "true";
    //Name sorting link
	wxString Out = pThis->m_Templates.sSharedList;
	if(pThis->m_Params.SharedSort == SHARED_SORT_NAME)
		Out.Replace("[SortName]", "sort=name&sortreverse=" + sSharedSortRev);
	else
		Out.Replace("[SortName]", "sort=name");
	//Size sorting Link
    if(pThis->m_Params.SharedSort == SHARED_SORT_SIZE)
		Out.Replace("[SortSize]", "sort=size&sortreverse=" + sSharedSortRev);
	else
		Out.Replace("[SortSize]", "sort=size");
	//Priority sorting Link
    if(pThis->m_Params.SharedSort == SHARED_SORT_PRIORITY)
		Out.Replace("[SortPriority]", "sort=priority&sortreverse=" + sSharedSortRev);
	else
		Out.Replace("[SortPriority]", "sort=priority");
    //Transferred sorting link
	if(pThis->m_Params.SharedSort == SHARED_SORT_TRANSFERRED)
	{
		if(pThis->m_Params.bSharedSortReverse)
            Out.Replace("[SortTransferred]", "sort=alltimetransferred&sortreverse=" + sSharedSortRev);
		else
			Out.Replace("[SortTransferred]", "sort=transferred&sortreverse=" + sSharedSortRev);
	}
	else
	if(pThis->m_Params.SharedSort == SHARED_SORT_ALL_TIME_TRANSFERRED)
	{
		if(pThis->m_Params.bSharedSortReverse)
            Out.Replace("[SortTransferred]", "sort=transferred&sortreverse=" + sSharedSortRev);
		else
			Out.Replace("[SortTransferred]", "sort=alltimetransferred&sortreverse=" + sSharedSortRev);
	}
	else
        Out.Replace("[SortTransferred]", "&sort=transferred&sortreverse=false");
    //Request sorting link
	if(pThis->m_Params.SharedSort == SHARED_SORT_REQUESTS)
	{
		if(pThis->m_Params.bSharedSortReverse)
            Out.Replace("[SortRequests]", "sort=alltimerequests&sortreverse=" + sSharedSortRev);
		else
			Out.Replace("[SortRequests]", "sort=requests&sortreverse=" + sSharedSortRev);
	}
	else
	if(pThis->m_Params.SharedSort == SHARED_SORT_ALL_TIME_REQUESTS)
	{
		if(pThis->m_Params.bSharedSortReverse)
            Out.Replace("[SortRequests]", "sort=requests&sortreverse=" + sSharedSortRev);
		else
			Out.Replace("[SortRequests]", "sort=alltimerequests&sortreverse=" + sSharedSortRev);
	}
	else
        Out.Replace("[SortRequests]", "&sort=requests&sortreverse=false");
    //Accepts sorting link
	if(pThis->m_Params.SharedSort == SHARED_SORT_ACCEPTS)
	{
		if(pThis->m_Params.bSharedSortReverse)
            Out.Replace("[SortAccepts]", "sort=alltimeaccepts&sortreverse=" + sSharedSortRev);
		else
			Out.Replace("[SortAccepts]", "sort=accepts&sortreverse=" + sSharedSortRev);
	}
	else
	if(pThis->m_Params.SharedSort == SHARED_SORT_ALL_TIME_ACCEPTS)
	{
		if(pThis->m_Params.bSharedSortReverse)
            Out.Replace("[SortAccepts]", "sort=accepts&sortreverse=" + sSharedSortRev);
		else
			Out.Replace("[SortAccepts]", "sort=alltimeaccepts&sortreverse=" + sSharedSortRev);
	}
	else
        Out.Replace("[SortAccepts]", "&sort=accepts&sortreverse=false");

	if(_ParseURL(Data.sURL, "reload") == "true")
	{
#warning logtext is private
	  wxString resultlog = ""; //_SpecialChars(theApp.emuledlg->logtext);	//Pick-up last line of the log
	  //resultlog = resultlog.TrimRight('\n');
	  //resultlog = resultlog.Mid(resultlog.ReverseFind('\n'));
	  Out.Replace("[Message]",resultlog);
	}
	else
        Out.Replace("[Message]","");

	Out.Replace("[Filename]", _GetPlainResString(IDS_DL_FILENAME));
	Out.Replace("[Priority]",  _GetPlainResString(IDS_PRIORITY));
    Out.Replace("[FileTransferred]",  _GetPlainResString(IDS_SF_TRANSFERRED));
    Out.Replace("[FileRequests]",  _GetPlainResString(IDS_SF_REQUESTS));
    Out.Replace("[FileAccepts]",  _GetPlainResString(IDS_SF_ACCEPTS));
	Out.Replace("[Size]", _GetPlainResString(IDS_DL_SIZE));
	Out.Replace("[Ed2klink]", _GetPlainResString(IDS_SW_LINK));
	Out.Replace("[Reload]", _GetPlainResString(IDS_SF_RELOAD));
	Out.Replace("[Session]", sSession);

	wxString OutE = pThis->m_Templates.sSharedLine; 
	OutE.Replace("[Ed2klink]", _GetPlainResString(IDS_SW_LINK));
    OutE.Replace("[PriorityUp]", _GetPlainResString(IDS_PRIORITY_UP));
    OutE.Replace("[PriorityDown]", _GetPlainResString(IDS_PRIORITY_DOWN));

	wxString OutE2 = pThis->m_Templates.sSharedLineChanged; 
	OutE.Replace("[Ed2klink]", _GetPlainResString(IDS_SW_LINK));
    OutE.Replace("[PriorityUp]", _GetPlainResString(IDS_PRIORITY_UP));
    OutE.Replace("[PriorityUp]", _GetPlainResString(IDS_PRIORITY_DOWN));

	CArray<SharedFiles*, SharedFiles*> SharedArray;
	// Populating array
	for (int ix=0;ix<theApp.sharedfiles->GetCount();ix++)
	{
		CCKey bufKey;
		CKnownFile* cur_file;
		cur_file=theApp.sharedfiles->GetFileByIndex(ix);// m_Files_map.GetNextAssoc(pos,bufKey,cur_file);

		SharedFiles* dFile=new SharedFiles();
		dFile->sFileName = _SpecialChars(cur_file->GetFileName());
		dFile->lFileSize = cur_file->GetFileSize();
		if (theApp.serverconnect->IsConnected()) 
		  dFile->sED2kLink = theApp.CreateED2kSourceLink(cur_file);
		else
		  dFile->sED2kLink = theApp.CreateED2kLink(cur_file);

		dFile->nFileTransferred = cur_file->statistic.GetTransfered();
		dFile->nFileAllTimeTransferred = cur_file->statistic.GetAllTimeTransfered();
		dFile->nFileRequests = cur_file->statistic.GetRequests();
		dFile->nFileAllTimeRequests = cur_file->statistic.GetAllTimeRequests();
		dFile->nFileAccepts = cur_file->statistic.GetAccepts();
		dFile->nFileAllTimeAccepts = cur_file->statistic.GetAllTimeAccepts();

		dFile->sFileHash = EncodeBase16(cur_file->GetFileHash(), 16);
#warning Wonder what IsAutoUpPriority is.. needs newer knownfile to work
#if 0
		if (cur_file->IsAutoUpPriority())
		{
			if (cur_file->GetUpPriority() == PR_NORMAL)
				dFile->sFilePriority = _GetPlainResString(IDS_PRIOAUTONORMAL);
			else if (cur_file->GetUpPriority() == PR_HIGH)
				dFile->sFilePriority = _GetPlainResString(IDS_PRIOAUTOHIGH);
			else if (cur_file->GetUpPriority() == PR_VERYHIGH)
				dFile->sFilePriority = _GetPlainResString(IDS_PRIOAUTORELEASE);
		}
		else
		{
			if (cur_file->GetUpPriority() == PR_VERYLOW)
				dFile->sFilePriority = _GetPlainResString(IDS_PRIOVERYLOW);
			else if (cur_file->GetUpPriority() == PR_LOW)
				dFile->sFilePriority = _GetPlainResString(IDS_PRIOLOW);
			else if (cur_file->GetUpPriority() == PR_NORMAL)
				dFile->sFilePriority = _GetPlainResString(IDS_PRIONORMAL);
			else if (cur_file->GetUpPriority() == PR_HIGH)
				dFile->sFilePriority = _GetPlainResString(IDS_PRIOHIGH);
			else if (cur_file->GetUpPriority() == PR_VERYHIGH)
				dFile->sFilePriority = _GetPlainResString(IDS_PRIORELEASE);
		}
		dFile->nFilePriority = cur_file->GetUpPriority();
		dFile->bFileAutoPriority = cur_file->IsAutoUpPriority();
#endif
		SharedArray.Add(dFile);
	}

	// Sorting (simple bubble sort, we don't have tons of data here)
	bool bSorted = true;
	
	for(int nMax = 0;bSorted && nMax < SharedArray.GetCount()*2; nMax++)
	{
		bSorted = false;
		for(int i = 0; i < SharedArray.GetCount() - 1; i++)
		{
			bool bSwap = false;
			switch(pThis->m_Params.SharedSort)
			{
			case SHARED_SORT_NAME:
				bSwap = SharedArray[i]->sFileName.CmpNoCase(SharedArray[i+1]->sFileName) > 0;
				break;
			case SHARED_SORT_SIZE:
				bSwap = SharedArray[i]->lFileSize < SharedArray[i+1]->lFileSize;
				break;
			case SHARED_SORT_TRANSFERRED:
				bSwap = SharedArray[i]->nFileTransferred < SharedArray[i+1]->nFileTransferred;
				break;
			case SHARED_SORT_ALL_TIME_TRANSFERRED:
				bSwap = SharedArray[i]->nFileAllTimeTransferred < SharedArray[i+1]->nFileAllTimeTransferred;
				break;
			case SHARED_SORT_REQUESTS:
				bSwap = SharedArray[i]->nFileRequests < SharedArray[i+1]->nFileRequests;
				break;
			case SHARED_SORT_ALL_TIME_REQUESTS:
				bSwap = SharedArray[i]->nFileAllTimeRequests < SharedArray[i+1]->nFileAllTimeRequests;
				break;
			case SHARED_SORT_ACCEPTS:
				bSwap = SharedArray[i]->nFileAccepts < SharedArray[i+1]->nFileAccepts;
				break;
			case SHARED_SORT_ALL_TIME_ACCEPTS:
				bSwap = SharedArray[i]->nFileAllTimeAccepts < SharedArray[i+1]->nFileAllTimeAccepts;
				break;
			case SHARED_SORT_PRIORITY:
				//Very low priority is define equal to 4 ! Must adapte sorting code
				if(SharedArray[i]->nFilePriority == 4)
				{
					if(SharedArray[i+1]->nFilePriority == 4)
						bSwap = false;
					else
						bSwap = true;
				}        
				else
					if(SharedArray[i+1]->nFilePriority == 4)
					{
						if(SharedArray[i]->nFilePriority == 4)
							bSwap = true;
						else
							bSwap = false;
					}
					else
						bSwap = SharedArray[i]->nFilePriority < SharedArray[i+1]->nFilePriority;
				break;
			}
			if(pThis->m_Params.bSharedSortReverse)
			{
				bSwap = !bSwap;
			}
			if(bSwap)
			{
				bSorted = true;
				SharedFiles* TmpFile = SharedArray[i];
				SharedArray[i] = SharedArray[i+1];
				SharedArray[i+1] = TmpFile;
			}
		}
	}
	// Displaying
	wxString sSharedList = "";
	for(int i = 0; i < SharedArray.GetCount(); i++)
	{
		char HTTPTempC[100] = "";
		wxString HTTPProcessData;
		if (SharedArray[i]->sFileHash == _ParseURL(Data.sURL,"hash") )
            HTTPProcessData = OutE2;
		else
            HTTPProcessData = OutE;

		HTTPProcessData.Replace("[FileName]", _SpecialChars(SharedArray[i]->sFileName));
		if(SharedArray[i]->sFileName.Length() > SHORT_FILENAME_LENGTH)
            HTTPProcessData.Replace("[ShortFileName]", _SpecialChars(SharedArray[i]->sFileName.Left(SHORT_FILENAME_LENGTH)) + "...");
		else
			HTTPProcessData.Replace("[ShortFileName]", _SpecialChars(SharedArray[i]->sFileName));

		sprintf(HTTPTempC, "%s %s",CastItoXBytes(SharedArray[i]->lFileSize).GetData(), _GetPlainResString(IDS_MBYTES).GetData());
		HTTPProcessData.Replace("[FileSize]", wxString(HTTPTempC));

		HTTPProcessData.Replace("[FileLink]", SharedArray[i]->sED2kLink);

		sprintf(HTTPTempC, "%s %s",CastItoXBytes(SharedArray[i]->nFileTransferred).GetData() , _GetPlainResString(IDS_MBYTES).GetData());
		HTTPProcessData.Replace("[FileTransferred]", wxString(HTTPTempC));

		sprintf(HTTPTempC, "%s %s ",CastItoXBytes(SharedArray[i]->nFileAllTimeTransferred).GetData(), _GetPlainResString(IDS_MBYTES).GetData());
		HTTPProcessData.Replace("[FileAllTimeTransferred]", wxString(HTTPTempC));

		sprintf(HTTPTempC, "%i", SharedArray[i]->nFileRequests);
		HTTPProcessData.Replace("[FileRequests]", wxString(HTTPTempC));

		sprintf(HTTPTempC, "%i", SharedArray[i]->nFileAllTimeRequests);
		HTTPProcessData.Replace("[FileAllTimeRequests]", wxString(HTTPTempC));

		sprintf(HTTPTempC, "%i", SharedArray[i]->nFileAccepts);
		HTTPProcessData.Replace("[FileAccepts]", wxString(HTTPTempC));

		sprintf(HTTPTempC, "%i", SharedArray[i]->nFileAllTimeAccepts);
		HTTPProcessData.Replace("[FileAllTimeAccepts]", wxString(HTTPTempC));

		HTTPProcessData.Replace("[Priority]", SharedArray[i]->sFilePriority);

		HTTPProcessData.Replace("[FileHash]", SharedArray[i]->sFileHash);

		uint8 upperpriority, lesserpriority;
		if(SharedArray[i]->nFilePriority == 4)
		{
			upperpriority = 0;	lesserpriority = 4;
		}
		else
		if(SharedArray[i]->nFilePriority == 0)
		{
			upperpriority = 1;	lesserpriority = 4;
		}
		else
		if(SharedArray[i]->nFilePriority == 1)
		{
			upperpriority = 2;	lesserpriority = 0;
		}
		else
		if(SharedArray[i]->nFilePriority == 2)
		{
			upperpriority = 3;	lesserpriority = 1;
		}
		else
		if(SharedArray[i]->nFilePriority == 3)
		{
			upperpriority = 5;	lesserpriority = 2;
		}
		else
		if(SharedArray[i]->nFilePriority == 5)
		{
			upperpriority = 5;	lesserpriority = 3;
		}
		if(SharedArray[i]->bFileAutoPriority)
		{
			upperpriority = 5;	lesserpriority = 3;
		}
        sprintf(HTTPTempC, "%i", upperpriority);
		HTTPProcessData.Replace("[PriorityUpLink]", "hash=" + SharedArray[i]->sFileHash +"&setpriority=" + wxString(HTTPTempC));
        sprintf(HTTPTempC, "%i", lesserpriority);
		HTTPProcessData.Replace("[PriorityDownLink]", "hash=" + SharedArray[i]->sFileHash +"&setpriority=" + wxString(HTTPTempC)); 

		sSharedList += HTTPProcessData;
	}
	// clear the array
	for(int qq=0;qq<SharedArray.GetCount();qq++) {
	  delete SharedArray[qq];
	}

	Out.Replace("[SharedFilesList]", sSharedList);
	Out.Replace("[Session]", sSession);

	return Out;
}

wxString CWebServer::_GetGraphs(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString Out = pThis->m_Templates.sGraphs;

	XBMDraw drawUp, drawDown;
	drawUp.CreateImage("image_up", WEB_GRAPH_WIDTH, WEB_GRAPH_HEIGHT);
	drawDown.CreateImage("image_down", WEB_GRAPH_WIDTH, WEB_GRAPH_HEIGHT);
	wxString sGraphDownload = "", sGraphUpload = "";
	int nPrevValUp = 0, nPrevValDown = 0;
	for(int i = 0; i < WEB_GRAPH_WIDTH; i++)
	{
		if(i % 4 == 0)
		{
			for(int j = 1; j < 6; j++)
			{
				drawDown.Plot(i, (WEB_GRAPH_HEIGHT / 6) * j);
				drawUp.Plot(i, (WEB_GRAPH_HEIGHT / 6) * j);
			}
		}
		int nVal;
		if(i < pThis->m_Params.PointsForWeb.GetCount())
		{
			int nI = i;
			if(pThis->m_Params.PointsForWeb.GetCount() < WEB_GRAPH_WIDTH)
				nI = WEB_GRAPH_WIDTH - pThis->m_Params.PointsForWeb.GetCount() + i;
			// download
			nVal = (pThis->m_Params.PointsForWeb[i]->download * WEB_GRAPH_HEIGHT) / (theApp.glob_prefs->GetMaxGraphDownloadRate() + 4);
			if(nVal > WEB_GRAPH_HEIGHT)
				nVal = WEB_GRAPH_HEIGHT;
			drawDown.Plot(nI, nVal);

			if(i != 0)
				drawDown.Line(nI - 1, nPrevValDown, nI, nVal);
			nPrevValDown = nVal;
			// upload
			nVal = (pThis->m_Params.PointsForWeb[i]->upload * WEB_GRAPH_HEIGHT) / (theApp.glob_prefs->GetMaxGraphUploadRate() + 4);
			if(nVal > WEB_GRAPH_HEIGHT)
				nVal = WEB_GRAPH_HEIGHT;
			drawUp.Plot(nI, nVal);
			if(i != 0)
				drawUp.Line(nI - 1, nPrevValUp, nI, nVal);
			nPrevValUp = nVal;
		}
	}

	CString sUpC, sDownC;
	drawUp.GetImage(sUpC);
	drawDown.GetImage(sDownC);

	wxString sUp,sDown;
	sUp=sUpC.GetData();
	sDown=sDownC.GetData();

	for (int ix=0;ix<sUp.Length()-1;ix++) {
		if (sUp.Mid(ix,2).Cmp("0x")==0) {
		  if (sUp.GetChar(ix+3)==','||sUp.GetChar(ix+3)==' ') {/*sUp.Insert(ix+2,'0');*/ix+=4;}
		}
	}
	for (int ix=0;ix<sDown.Length()-1;ix++) {
		if (sDown.Mid(ix,2).Cmp("0x")==0) {
		  if (sDown.GetChar(ix+3)==','||sDown.GetChar(ix+3)==' ') {/*sDown.Insert(ix+2,'0');*/ix+=4;}
		}
	}

	Out.Replace("[GraphDownload]", sDown + drawDown.GetImageTag());
	Out.Replace("[GraphUpload]", sUp + drawUp.GetImageTag());
	Out.Replace("[TxtDownload]", _GetPlainResString(IDS_DOWNLOAD));
	Out.Replace("[TxtUpload]", _GetPlainResString(IDS_PW_CON_UPLBL));
	wxString sScale;

	sScale.Printf("%s %s", _GetPlainResString(IDS_TIME).GetData(), 
		CastSecondsToHM(theApp.glob_prefs->GetTrafficOMeterInterval() * WEB_GRAPH_WIDTH).GetData() );

	wxString s1, s2;
	s1.Printf("%d " + _GetPlainResString(IDS_KBYTESEC) + ", ", theApp.glob_prefs->GetMaxGraphDownloadRate() + 4);
	s2.Printf("%d " + _GetPlainResString(IDS_KBYTESEC) + ", ", theApp.glob_prefs->GetMaxGraphUploadRate() + 4);
	s1 += sScale; s2 += sScale;
	Out.Replace("[MaxDownload]", s1);
	Out.Replace("[MaxUpload]", s2);

	return Out;
}

wxString CWebServer::_GetAddServerBox(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession = _ParseURL(Data.sURL, "ses");

	if (!IsSessionAdmin(Data,sSession)) return "";

	wxString Out = pThis->m_Templates.sAddServerBox;
	if(_ParseURL(Data.sURL, "addserver") == "true")
	{
		CServer* nsrv = new CServer(atoi((char*)_ParseURL(Data.sURL, "serverport").GetData()), (char*)_ParseURL(Data.sURL, "serveraddr").GetData() );
		theApp.serverlist->AddServer(nsrv);
#warning logtext is private
		wxString resultlog = "";//_SpecialChars(theApp.emuledlg->logtext);	//Pick-up last line of the log
		//resultlog = resultlog.TrimRight('\n');
		//resultlog = resultlog.Mid(resultlog.ReverseFind('\n'));
		Out.Replace("[Message]",resultlog);
	}
	else
		if(_ParseURL(Data.sURL, "updateservermetfromurl") == "true")
		{
		  // uh-oh. this can't succeed....
#warning FATAL. Trying to call main threads method
				theApp.emuledlg->serverwnd->UpdateServerMetFromURL(_ParseURL(Data.sURL, "servermeturl"));
#warning logtext is private
				wxString resultlog ="";// _SpecialChars(theApp.emuledlg->logtext);
				//resultlog = resultlog.TrimRight('\n');
				//resultlog = resultlog.Mid(resultlog.ReverseFind('\n'));
				Out.Replace("[Message]",resultlog);
		}
		else
		Out.Replace("[Message]", "");
    Out.Replace("[AddServer]", _GetPlainResString(IDS_SV_NEWSERVER));
	Out.Replace("[IP]", _GetPlainResString(IDS_SV_ADDRESS));
	Out.Replace("[Port]", _GetPlainResString(IDS_SV_PORT));
	Out.Replace("[Name]", _GetPlainResString(IDS_SW_NAME));
	Out.Replace("[Add]", _GetPlainResString(IDS_SV_ADD));
	Out.Replace("[UpdateServerMetFromURL]", _GetPlainResString(IDS_SV_MET));
	Out.Replace("[URL]", _GetPlainResString(IDS_SV_URL));
	Out.Replace("[Apply]", _GetPlainResString(IDS_PW_APPLY));

	return Out;
}
wxString	CWebServer::_GetWebSearch(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession = _ParseURL(Data.sURL, "ses");
    
	wxString Out = pThis->m_Templates.sWebSearch;
	if(_ParseURL(Data.sURL, "tosearch") != "")
	{
		wxString query;
		wxString tosearch = _ParseURL(Data.sURL, "tosearch");
		query = "http://www.filedonkey.com/fdsearch/index.php?media=";
		query += _ParseURL(Data.sURL, "media");
		tosearch = URLEncode(tosearch);
		tosearch.Replace("%20","+");
		query += "&pattern=";
		query += _ParseURL(Data.sURL, "tosearch");
		query += "&action=search&name=FD-Search&op=modload&file=index&requestby=emule";
		Out += "\n<script language=\"javascript\">";
		Out += "\n searchwindow=window.open('"+ query + "','searchwindow');";
		Out += "\n</script>";
	}
	Out.Replace("[Session]", sSession);
	Out.Replace("[WebSearch]", _GetPlainResString(IDS_SW_WEBBASED));
	Out.Replace("[Name]", _GetPlainResString(IDS_SW_NAME));
	Out.Replace("[Type]", _GetPlainResString(IDS_TYPE));
	Out.Replace("[Any]", _GetPlainResString(IDS_SEARCH_ANY));
	Out.Replace("[Audio]", _GetPlainResString(IDS_SEARCH_AUDIO));
	Out.Replace("[Video]", _GetPlainResString(IDS_SEARCH_VIDEO));
	Out.Replace("[Other]", "Other");
	Out.Replace("[Search]", _GetPlainResString(IDS_SW_START));
	
	return Out;
}

wxString CWebServer::_GetLog(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession = _ParseURL(Data.sURL, "ses");

	wxString Out = pThis->m_Templates.sLog;

	if (_ParseURL(Data.sURL, "clear") == "yes")
	{
		theApp.emuledlg->ResetLog();
	}
	Out.Replace("[Clear]", _GetPlainResString(IDS_PW_RESET));
#warning logtext is private
	//Out.Replace("[Log]", _SpecialChars(theApp.emuledlg->logtext));
	Out.Replace("[Session]", sSession);

	return Out;
}

wxString CWebServer::_GetServerInfo(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession = _ParseURL(Data.sURL, "ses");

	wxString Out = pThis->m_Templates.sServerInfo;

	if (_ParseURL(Data.sURL, "clear") == "yes")
	{
#warning cant do this
	  //theApp.emuledlg->serverwnd.servermsgbox.SetWindowText("");
	}
	Out.Replace("[Clear]", _GetPlainResString(IDS_PW_RESET));
#warning cant do this
	//Out.Replace("[ServerInfo]", _SpecialChars(theApp.emuledlg->serverwnd.servermsgbox.GetHyperText()->GetText()));
	Out.Replace("[Session]", sSession);

	return Out;
}

wxString CWebServer::_GetDebugLog(ThreadData Data)
{
#warning We dont even have decent debug log
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession = _ParseURL(Data.sURL, "ses");

	wxString Out = pThis->m_Templates.sDebugLog;

	if (_ParseURL(Data.sURL, "clear") == "yes")
	{
	  //theApp.emuledlg->ResetDebugLog();
	}
	Out.Replace("[Clear]", _GetPlainResString(IDS_PW_RESET));
	//Out.Replace("[DebugLog]", _SpecialChars(theApp.emuledlg->debuglog));
	Out.Replace("[Session]", sSession);

	return Out;
}

wxString CWebServer::_GetStats(ThreadData Data)
{
  printf("***_GetStats arrived\n");
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession = _ParseURL(Data.sURL, "ses");

	// refresh statistics.. ARGH. NO NO NO NO
	// (it will be done in statisticsdlg and in main thread)
	//theApp.emuledlg->ShowStatistics();

	wxString Out = pThis->m_Templates.sStats;
	Out.Replace("[Stats]", theApp.emuledlg->statisticswnd->ExportHTML());
	return Out;
}

wxString CWebServer::_GetPreferences(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession = _ParseURL(Data.sURL, "ses");

	wxString Out = pThis->m_Templates.sPreferences;
	Out.Replace("[Session]", sSession);

	if ((_ParseURL(Data.sURL, "saveprefs") == "true") && IsSessionAdmin(Data,sSession) ) {
		if(_ParseURL(Data.sURL, "gzip") == "true" || _ParseURL(Data.sURL, "gzip") == "on")
		{
			theApp.glob_prefs->SetWebUseGzip(true);
		}
		if(_ParseURL(Data.sURL, "gzip") == "false" || _ParseURL(Data.sURL, "gzip") == "")
		{
			theApp.glob_prefs->SetWebUseGzip(false);
		}
		if(_ParseURL(Data.sURL, "showuploadqueue") == "true" || _ParseURL(Data.sURL, "showuploadqueue") == "on" )
		{
			pThis->m_Params.bShowUploadQueue = true;
		}
		if(_ParseURL(Data.sURL, "showuploadqueue") == "false" || _ParseURL(Data.sURL, "showuploadqueue") == "")
		{
			pThis->m_Params.bShowUploadQueue = false;
		}
		if(_ParseURL(Data.sURL, "refresh") != "")
		{
			theApp.glob_prefs->SetWebPageRefresh(atoi(_ParseURL(Data.sURL, "refresh")));
		}
		if(_ParseURL(Data.sURL, "maxdown") != "")
		{
			if(atoi(_ParseURL(Data.sURL, "maxdown"))>0)
				theApp.glob_prefs->SetMaxDownload(atoi(_ParseURL(Data.sURL, "maxdown")));
			else
				theApp.glob_prefs->SetMaxDownload(65535);
		}
		if(_ParseURL(Data.sURL, "maxup") != "")
		{
			if(atoi(_ParseURL(Data.sURL, "maxup"))>0)
				theApp.glob_prefs->SetMaxUpload(atoi(_ParseURL(Data.sURL, "maxup")));
			else
				theApp.glob_prefs->SetMaxUpload(65535);
		}
		if(_ParseURL(Data.sURL, "maxcapdown") != "")
		{
			theApp.glob_prefs->SetMaxGraphDownloadRate(atoi(_ParseURL(Data.sURL, "maxcapdown")));
		}
		if(_ParseURL(Data.sURL, "maxcapup") != "")
		{
			theApp.glob_prefs->SetMaxGraphUploadRate(atoi(_ParseURL(Data.sURL, "maxcapup")));
		}

		if(_ParseURL(Data.sURL, "maxsources") != "")
		{
			theApp.glob_prefs->SetMaxSourcesPerFile(atoi(_ParseURL(Data.sURL, "maxsources")));
		}
		if(_ParseURL(Data.sURL, "maxconnections") != "")
		{
			theApp.glob_prefs->SetMaxConnections(atoi(_ParseURL(Data.sURL, "maxconnections")));
		}
		if(_ParseURL(Data.sURL, "maxconnectionsperfive") != "")
		{
			theApp.glob_prefs->SetMaxConsPerFive(atoi(_ParseURL(Data.sURL, "maxconnectionsperfive")));
		}

		theApp.glob_prefs->SetTransferFullChunks((_ParseURL(Data.sURL, "fullchunks") == "on"));
		theApp.glob_prefs->SetPreviewPrio((_ParseURL(Data.sURL, "firstandlast") == "on"));
	}

	// Fill form
	if(theApp.glob_prefs->GetWebUseGzip())
	{
		Out.Replace("[UseGzipVal]", "checked");
	}
	else
	{
		Out.Replace("[UseGzipVal]", "");
	}
    if(pThis->m_Params.bShowUploadQueue)
	{
		Out.Replace("[ShowUploadQueueVal]", "checked");
	}
	else
	{
		Out.Replace("[ShowUploadQueueVal]", "");
	}
	if(theApp.glob_prefs->GetPreviewPrio())
	{
		Out.Replace("[FirstAndLastVal]", "checked");
	}
	else
	{
		Out.Replace("[FirstAndLastVal]", "");
	}
	if(theApp.glob_prefs->TransferFullChunks())
	{
		Out.Replace("[FullChunksVal]", "checked");
	}
	else
	{
		Out.Replace("[FullChunksVal]", "");
	}
	wxString sRefresh;
	
	sRefresh.Printf("%d", theApp.glob_prefs->GetWebPageRefresh());
	Out.Replace("[RefreshVal]", sRefresh);

	sRefresh.Printf("%d", theApp.glob_prefs->GetMaxSourcePerFile());
	Out.Replace("[MaxSourcesVal]", sRefresh);

	sRefresh.Printf("%d", theApp.glob_prefs->GetMaxConnections());
	Out.Replace("[MaxConnectionsVal]", sRefresh);

	sRefresh.Printf("%d", theApp.glob_prefs->GetMaxConperFive());
	Out.Replace("[MaxConnectionsPer5Val]", sRefresh);

	Out.Replace("[KBS]", _GetPlainResString(IDS_KBYTESEC)+":");
	Out.Replace("[FileSettings]", wxString(_GetPlainResString(IDS_WEB_FILESETTINGS)+":"));
	Out.Replace("[LimitForm]", _GetPlainResString(IDS_WEB_CONLIMITS)+":");
	Out.Replace("[MaxSources]", _GetPlainResString(IDS_PW_MAXSOURCES)+":");
	Out.Replace("[MaxConnections]", _GetPlainResString(IDS_PW_MAXC)+":");
	Out.Replace("[MaxConnectionsPer5]", _GetPlainResString(IDS_MAXCON5SECLABEL)+":");
	Out.Replace("[UseGzipForm]", _GetPlainResString(IDS_WEB_GZIP_COMPRESSION));
	Out.Replace("[UseGzipComment]", _GetPlainResString(IDS_WEB_GZIP_COMMENT));
	Out.Replace("[ShowUploadQueueForm]", _GetPlainResString(IDS_WEB_SHOW_UPLOAD_QUEUE));
	Out.Replace("[ShowUploadQueueComment]", _GetPlainResString(IDS_WEB_UPLOAD_QUEUE_COMMENT));
	Out.Replace("[ShowQueue]", _GetPlainResString(IDS_WEB_SHOW_UPLOAD_QUEUE));
	Out.Replace("[HideQueue]", _GetPlainResString(IDS_WEB_HIDE_UPLOAD_QUEUE));
	Out.Replace("[RefreshTimeForm]", _GetPlainResString(IDS_WEB_REFRESH_TIME));
	Out.Replace("[RefreshTimeComment]", _GetPlainResString(IDS_WEB_REFRESH_COMMENT));
	Out.Replace("[SpeedForm]", _GetPlainResString(IDS_SPEED_LIMITS));
	Out.Replace("[MaxDown]", _GetPlainResString(IDS_DOWNLOAD));
	Out.Replace("[MaxUp]", _GetPlainResString(IDS_PW_CON_UPLBL));
	Out.Replace("[SpeedCapForm]", _GetPlainResString(IDS_CAPACITY_LIMITS));
	Out.Replace("[MaxCapDown]", _GetPlainResString(IDS_DOWNLOAD));
	Out.Replace("[MaxCapUp]", _GetPlainResString(IDS_PW_CON_UPLBL));
	Out.Replace("[TryFullChunks]", _GetPlainResString(IDS_FULLCHUNKTRANS));
	Out.Replace("[FirstAndLast]", _GetPlainResString(IDS_DOWNLOADMOVIECHUNKS));
	Out.Replace("[WebControl]", _GetPlainResString(IDS_WEB_CONTROL));
	Out.Replace("[eMuleAppName]", "eMule");
	Out.Replace("[Apply]", _GetPlainResString(IDS_PW_APPLY));

	wxString sT;
	int n = (int)theApp.glob_prefs->GetMaxDownload();
	if(n < 0 || n == 65535) n = 0;
	sT.Printf("%d", n);
	Out.Replace("[MaxDownVal]", sT);
	n = (int)theApp.glob_prefs->GetMaxUpload();
	if(n < 0 || n == 65535) n = 0;
	sT.Printf("%d", n);
	Out.Replace("[MaxUpVal]", sT);
	sT.Printf("%d", theApp.glob_prefs->GetMaxGraphDownloadRate());
	Out.Replace("[MaxCapDownVal]", sT);
	sT.Printf("%d", theApp.glob_prefs->GetMaxGraphUploadRate());
	Out.Replace("[MaxCapUpVal]", sT);

	return Out;
}

wxString CWebServer::_GetLoginScreen(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession = _ParseURL(Data.sURL, "ses");

	wxString Out = "";

	Out += pThis->m_Templates.sLogin;

	Out.Replace("[CharSet]", _GetWebCharSet());
	Out.Replace("[eMulePlus]", "eMule");
	Out.Replace("[eMuleAppName]", "eMule");
	Out.Replace("[version]", CURRENT_VERSION_LONG);
	Out.Replace("[Login]", _GetPlainResString(IDS_WEB_LOGIN));
	Out.Replace("[EnterPassword]", _GetPlainResString(IDS_WEB_ENTER_PASSWORD));
	Out.Replace("[LoginNow]", _GetPlainResString(IDS_WEB_LOGIN_NOW));
	Out.Replace("[WebControl]", _GetPlainResString(IDS_WEB_CONTROL));

	return Out;
}

wxString CWebServer::_GetConnectedServer(ThreadData Data)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession = _ParseURL(Data.sURL, "ses");

	wxString HTTPTemp = "";
	char	HTTPTempC[100] = "";
	wxString OutS = pThis->m_Templates.sConnectedServer;
	OutS.Replace("[ConnectedServer]", _GetPlainResString(IDS_PW_SERVER));
	OutS.Replace("[Servername]", _GetPlainResString(IDS_SL_SERVERNAME));
	OutS.Replace("[Status]", _GetPlainResString(IDS_STATUS));
	OutS.Replace("[Usercount]", _GetPlainResString(IDS_LUSERS));
	OutS.Replace("[Action]", _GetPlainResString(IDS_CONNECTING));
	OutS.Replace("[URL_Disconnect]", IsSessionAdmin(Data,sSession)?wxString("/?ses=" + sSession + "&w=server&c=disconnect"):GetPermissionDenied());
	OutS.Replace("[URL_Connect]", IsSessionAdmin(Data,sSession)?wxString("/?ses=" + sSession + "&w=server&c=connect"):GetPermissionDenied());
	OutS.Replace("[Disconnect]", _GetPlainResString(IDS_IRC_DISCONNECT));
	OutS.Replace("[Connect]", _GetPlainResString(IDS_CONNECTTOANYSERVER));
	OutS.Replace("[URL_ServerOptions]", IsSessionAdmin(Data,sSession)?wxString("/?ses=" + sSession + "&w=server&c=options"):GetPermissionDenied());
	OutS.Replace("[ServerOptions]", wxString(_GetPlainResString(IDS_SERVER)+_GetPlainResString(IDS_EM_PREFS)));
	OutS.Replace("[WebSearch]", _GetPlainResString(IDS_SW_WEBBASED));

	if (theApp.serverconnect->IsConnected()) {
		if(!theApp.serverconnect->IsLowID())
			OutS.Replace("[1]", _GetPlainResString(IDS_CONNECTED));
		else
			OutS.Replace("[1]", _GetPlainResString(IDS_CONNECTED) + " (" + _GetPlainResString(IDS_IDLOW) + ")");

		CServer* cur_server = theApp.serverconnect->GetCurrentServer();
		OutS.Replace("[2]", wxString(cur_server->GetListName()));

		sprintf(HTTPTempC, "%10i", cur_server->GetUsers());
		HTTPTemp = HTTPTempC;												
		OutS.Replace("[3]", HTTPTemp);

	} else if (theApp.serverconnect->IsConnecting()) {
		OutS.Replace("[1]", _GetPlainResString(IDS_CONNECTING));
		OutS.Replace("[2]", "");
		OutS.Replace("[3]", "");
	} else {
		OutS.Replace("[1]", _GetPlainResString(IDS_DISCONNECTED));
		OutS.Replace("[2]", "");
		OutS.Replace("[3]", "");
	}
	return OutS;
}

// We have to add gz-header and some other stuff
// to standard zlib functions
// in order to use gzip in web pages
int CWebServer::_GzipCompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)
{ 
	const static int gz_magic[2] = {0x1f, 0x8b}; // gzip magic header
	int err;
	uLong crc;
	z_stream stream = {0};
	stream.zalloc = (alloc_func)0;
	stream.zfree = (free_func)0;
	stream.opaque = (voidpf)0;
	crc = crc32(0L, Z_NULL, 0);
	// init Zlib stream
	// NOTE windowBits is passed < 0 to suppress zlib header
	err = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
	if (err != Z_OK)
		return err;

	sprintf((char*)dest , "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
		Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, 255);
	// wire buffers
	stream.next_in = (Bytef*) source ;
	stream.avail_in = (uInt)sourceLen;
	stream.next_out = ((Bytef*) dest) + 10;
	stream.avail_out = *destLen - 18;
	// doit
	err = deflate(&stream, Z_FINISH);
	if (err != Z_STREAM_END)
	{
		deflateEnd(&stream);
		return err;
	}
	err = deflateEnd(&stream);
	crc = crc32(crc, (const Bytef *) source ,  sourceLen );
	//CRC
	*(((Bytef*) dest)+10+stream.total_out) = (Bytef)(crc & 0xFF);
	*(((Bytef*) dest)+10+stream.total_out+1) = (Bytef)((crc>>8) & 0xFF);
	*(((Bytef*) dest)+10+stream.total_out+2) = (Bytef)((crc>>16) & 0xFF);
	*(((Bytef*) dest)+10+stream.total_out+3) = (Bytef)((crc>>24) & 0xFF);
	// Length
	*(((Bytef*) dest)+10+stream.total_out+4) = (Bytef)( sourceLen  & 0xFF);
	*(((Bytef*) dest)+10+stream.total_out+5) = (Bytef)(( sourceLen >>8) & 0xFF);
	*(((Bytef*) dest)+10+stream.total_out+6) = (Bytef)(( sourceLen >>16) &	0xFF);
	*(((Bytef*) dest)+10+stream.total_out+7) = (Bytef)(( sourceLen >>24) &	0xFF);
	// return  destLength
	*destLen = 10 + stream.total_out + 8;
	return err;
}

bool CWebServer::_IsLoggedIn(ThreadData Data, long lSession)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	_RemoveTimeOuts(Data,lSession);

	// find our session
	// i should have used CMap there, but i like CArray more ;-)
	for(int i = 0; i < pThis->m_Params.Sessions.GetSize(); i++)
	{
		if(pThis->m_Params.Sessions[i]->lSession == lSession && lSession != 0)
		{
			// if found, also reset expiration time
			pThis->m_Params.Sessions[i]->startTime = time(NULL);
			return true;
		}
	}

	return false;
}

void CWebServer::_RemoveTimeOuts(ThreadData Data, long lSession) {
	// remove expired sessions
	CWebServer *pThis = (CWebServer *)Data.pThis;
	pThis->UpdateSessionCount();
}

bool CWebServer::_RemoveSession(ThreadData Data, long lSession)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	// find our session
	for(int i = 0; i < pThis->m_Params.Sessions.GetSize(); i++)
	{
		if(pThis->m_Params.Sessions[i]->lSession == lSession && lSession != 0)
		{
		// delete it!!!!!!!
			pThis->m_Params.Sessions.RemoveAt(i);
			// DONT!!
			//theApp.emuledlg->AddLogLine(true,GetResString(IDS_WEB_SESSIONEND),lSession);
			return true;
		}
	}
	return false;
}

Session CWebServer::GetSessionByID(ThreadData Data,long sessionID) {
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis != NULL) {
		for(int i = 0; i < pThis->m_Params.Sessions.GetSize(); i++)
		{
			if(pThis->m_Params.Sessions[i]->lSession == sessionID && sessionID != 0)
				return *(pThis->m_Params.Sessions.GetAt(i));
		}
	}

	Session ses;
	ses.admin=false;
	ses.startTime = 0;

	return ses;
}

bool CWebServer::IsSessionAdmin(ThreadData Data,wxString SsessionID){
	long sessionID=atoll(SsessionID);
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis != NULL) {
		for(int i = 0; i < pThis->m_Params.Sessions.GetSize(); i++)
		{
			if(pThis->m_Params.Sessions[i]->lSession == sessionID && sessionID != 0)
				return pThis->m_Params.Sessions[i]->admin;
		}
	}
	return false;
}

wxString CWebServer::GetPermissionDenied() {
	return "javascript:alert(\'"+_GetPlainResString(IDS_ACCESSDENIED)+"\')";
}

bool CWebServer::_GetFileHash(wxString sHash, uchar *FileHash)
{
	char hex_byte[3];
	int byte;
	hex_byte[2] = '\0';
	for (int i = 0; i < 16; i++) 
	{
		hex_byte[0] = sHash.GetChar(i*2);
		hex_byte[1] = sHash.GetChar((i*2 + 1));
		sscanf(hex_byte, "%02x", &byte);
		FileHash[i] = (uchar)byte;
	}
	return true;
}

wxString	CWebServer::_GetPlainResString(UINT nID, bool noquot)
{
	wxString sRet = GetResString(nID);
	sRet.Replace("&", "");
	if(noquot)
	{
        sRet.Replace("'", "\\'");
		sRet.Replace("\n", "\\n");
	}
	return sRet;
}

// EC + kuchin
wxString	CWebServer::_GetWebCharSet()
{
#if 0
	switch (theApp.glob_prefs->GetLanguageID())
	{
		case MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT):				return "windows-1250";
		case MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT):				return "windows-1251";
		case MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT):				return "ISO-8859-7";
		case MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT):				return "ISO-8859-8";
		case MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT):				return "EUC-KR";
		case MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED):	return "GB2312";
		case MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_TRADITIONAL):	return "Big5";
		case MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT):			return "windows-1257";
	}
#endif
	// Western (Latin) includes Catalan, Danish, Dutch, English, Faeroese, Finnish, French,
	// German, Galician, Irish, Icelandic, Italian, Norwegian, Portuguese, Spanish and Swedish
	return "ISO-8859-1";
}

// Ornis: creating the progressbar. colored if ressources are given/available
wxString CWebServer::_GetDownloadGraph(ThreadData Data,wxString filehash)
{
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	CPartFile* cur_file;
	uchar fileid[16];
	DecodeBase16(filehash.GetData(),filehash.Length(),fileid);
	cur_file=theApp.downloadqueue->GetFileByID(fileid);

	wxString resPath=pThis->m_Templates.sResDir;
	if (resPath=="" && wxFileName::FileExists(wxString(theApp.glob_prefs->GetAppDir()) +"webserver/black.gif")) {
		resPath.Printf("file://%swebserver/",theApp.glob_prefs->GetAppDir());
		resPath.Replace("\\","/");
	}
	
	wxString Out = "";
	// simple style if ressources cant be found
	if (resPath=="") {
		XBMDraw bar;
		int proc=cur_file->GetPercentCompleted();
		if (proc<0) proc=0; if (proc>100) proc=100;
		int size=((float)proc/(float)100)*(pThis->m_Templates.iProgressbarWidth);
		if (proc>0) bar.CreateImage("img_progressbar", size, 10,255);
			else bar.CreateImage("img_progressbar", 8, 10,0);

		wxString sBar;
		CString sBarC;
		bar.GetImage(sBarC);
		sBar=sBarC.GetData();
		for (int ix=0;ix<sBar.Length()-1;ix++) {
			if (sBar.Mid(ix,2).Cmp("0x")==0) {
#warning no insert in wxstring
			  if (sBar.GetChar(ix+3)==','||sBar.GetChar(ix+3)==' ') {/*sBar.Insert(ix+2,'0');*/ix+=4;}
			}
		}
		Out.Printf("%s\n<img src=\"javascript:img_progressbar\">",sBar.GetData());

	// cool style
	} else {
		wxString progresscolor[7];
		progresscolor[0]="green.gif";
		progresscolor[1]="black.gif";
		progresscolor[2]="yellow.gif";
		progresscolor[3]="blue.gif";
		progresscolor[4]="red.gif";
		progresscolor[5]="greenpercent.gif";
		progresscolor[6]="transparent.gif";

#warning PartFile needs work.
		wxString s_ChunkBar=cur_file->GetProgressString(pThis->m_Templates.iProgressbarWidth);

		// and now make a graph out of the array - need to be in a progressive way
		uint8 lastcolor=1;
		uint16 lastindex=0;
		wxString temp;
		for (uint16 i=0;i<pThis->m_Templates.iProgressbarWidth;i++) {
			if (lastcolor!= atoi(s_ChunkBar.Mid(i,1))  ) {
				if (i>lastindex) {
				  //temp.Printf("<img src=\"%s%s\" height=10 width=%i>",resPath.GetData(),progresscolor[lastcolor].GetData(),i-lastindex);
				  temp.Printf("<img src=\"%s\" height=10 width=%i>",progresscolor[lastcolor].GetData(),i-lastindex);
				  Out+=temp;
				}
				lastcolor=atoi(s_ChunkBar.Mid(i,1));
				lastindex=i;
			}
		}
		//temp.Printf("<img src=\"%s%s\" height=10 width=%i>",resPath.GetData(),progresscolor[lastcolor].GetData(),pThis->m_Templates.iProgressbarWidth-lastindex);
		temp.Printf("<img src=\"%s\" height=10 width=%i>",progresscolor[lastcolor].GetData(),pThis->m_Templates.iProgressbarWidth-lastindex);
		Out+=temp;

		int complx=(int)((pThis->m_Templates.iProgressbarWidth/100)*cur_file->GetPercentCompleted());

		//if(complx>0) temp.Printf("<img src=\"%s%s\" height=3 width=%i><br>",resPath.GetData(),progresscolor[5].GetData(),complx);  
		//else temp.Printf("<img src=\"%s%s\" height=3 width=5><br>",resPath.GetData(),progresscolor[6].GetData());
		if(complx>0) temp.Printf("<img src=\"%s\" height=3 width=%i><br>",progresscolor[5].GetData(),complx);  
		else temp.Printf("<img src=\"%s\" height=3 width=5><br>",progresscolor[6].GetData());
		Out=temp+Out;
	}
	return Out;
}

wxString	CWebServer::_GetSearch(ThreadData Data)
{
#if 0
	CWebServer *pThis = (CWebServer *)Data.pThis;
	if(pThis == NULL)
		return "";

	wxString sSession = _ParseURL(Data.sURL, "ses");
	wxString Out = pThis->m_Templates.sSearch;

	if (_ParseURL(Data.sURL, "downloads") != "" && IsSessionAdmin(Data,sSession) ) {
		wxString downloads=_ParseURLArray(Data.sURL,"downloads");
				
		wxString resToken;
		int curPos=0;
		resToken= downloads.Tokenize("|",curPos);
		while (resToken != "")
		{
			uchar fileid[16];
			DecodeBase16(resToken.GetBuffer(),resToken.GetLength(),fileid);
			theApp.searchlist->AddFileToDownloadByHash(fileid);
			resToken= downloads.Tokenize("|",curPos);
		}
	}

	if(_ParseURL(Data.sURL, "tosearch") != "" && IsSessionAdmin(Data,sSession) )
	{
		// perform search
		theApp.emuledlg->searchwnd.DeleteAllSearchs();
		theApp.emuledlg->searchwnd.DoNewSearch(
			_ParseURL(Data.sURL, "tosearch"),
			_ParseURL(Data.sURL, "type"),
			atol(_ParseURL(Data.sURL, "min"))*1048576,
			atol(_ParseURL(Data.sURL, "max"))*1048576,
			atoi(_ParseURL(Data.sURL, "avail")),
			_ParseURL(Data.sURL, "ext"),
			(_ParseURL(Data.sURL, "global")=="on")
			);
		Out.Replace("[Message]",_GetPlainResString(IDS_SW_SEARCHINGINFO));
	}
	else if(_ParseURL(Data.sURL, "tosearch") != "" && !IsSessionAdmin(Data,sSession) ) {
		Out.Replace("[Message]",_GetPlainResString(IDS_ACCESSDENIED));
	}
	else Out.Replace("[Message]","");

	wxString result=pThis->m_Templates.sSearchHeader +theApp.searchlist->GetWebList(pThis->m_Templates.sSearchResultLine);

	Out.Replace("[SEARCHINFOMSG]","");
	Out.Replace("[RESULTLIST]", result);
	Out.Replace("[Result]", GetResString(IDS_SW_RESULT) );
	Out.Replace("[Session]", sSession);
	Out.Replace("[WebSearch]", _GetPlainResString(IDS_SW_WEBBASED));
	Out.Replace("[Name]", _GetPlainResString(IDS_SW_NAME));
	Out.Replace("[Type]", _GetPlainResString(IDS_TYPE));
	Out.Replace("[Any]", _GetPlainResString(IDS_SEARCH_ANY));
	Out.Replace("[Audio]", _GetPlainResString(IDS_SEARCH_AUDIO));
	Out.Replace("[Image]", _GetPlainResString(IDS_SEARCH_PICS));
	Out.Replace("[Video]", _GetPlainResString(IDS_SEARCH_VIDEO));
	Out.Replace("[Other]", "Other");
	Out.Replace("[Search]", _GetPlainResString(IDS_SW_SEARCHBOX));
	Out.Replace("[RefetchResults]", _GetPlainResString(IDS_SW_REFETCHRES));
	Out.Replace("[Download]", _GetPlainResString(IDS_DOWNLOAD));
	Out.Replace("[Filesize]", _GetPlainResString(IDS_DL_SIZE));
	Out.Replace("[Sources]", _GetPlainResString(IDS_DL_SOURCES));
	Out.Replace("[Filehash]", _GetPlainResString(IDS_FILEHASH));
	Out.Replace("[Filename]", _GetPlainResString(IDS_DL_FILENAME));
	Out.Replace("[WebSearch]", _GetPlainResString(IDS_SW_WEBBASED));

	Out.Replace("[SizeMin]", _GetPlainResString(IDS_SEARCHMINSIZE));
	Out.Replace("[SizeMax]", _GetPlainResString(IDS_SEARCHMAXSIZE));
	Out.Replace("[Availabl]", _GetPlainResString(IDS_SEARCHAVAIL));
	Out.Replace("[Extention]", _GetPlainResString(IDS_SEARCHEXTENTION));
	Out.Replace("[Global]", _GetPlainResString(IDS_GLOBALSEARCH2));
	Out.Replace("[MB]", _GetPlainResString(IDS_MBYTES));
	
	return Out;
#endif
	return "";
}

int CWebServer::UpdateSessionCount() {

	int oldvalue=m_Params.Sessions.GetSize();
	for(int i = 0; i < m_Params.Sessions.GetSize();)
	{
	  //CTimeSpan ts = CTime::GetCurrentTime() - m_Params.Sessions[i].startTime;
	  time_t ts=time(NULL)-m_Params.Sessions[i]->startTime;
	  if(ts > SESSION_TIMEOUT_SECS) {
	    m_Params.Sessions.RemoveAt(i);
	  }
	  else
	    i++;
	}

	if (oldvalue!=m_Params.Sessions.GetSize()) theApp.emuledlg->serverwnd->UpdateMyInfo();

	return m_Params.Sessions.GetCount();
}
